diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index d50d38d848..ad311a371a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -10,6 +10,12 @@ This is to ensure large feature PRs are discussed with the community first, before starting work on it. If the community does not want this feature or it is not relevant for Open WebUI as a project, it can be identified in the discussion before working on the feature and submitting the PR. + + **Before submitting, make sure you've checked the following:** - [ ] **Target branch:** Verify that the pull request targets the `dev` branch. **PRs targeting `main` will be immediately closed.** diff --git a/CHANGELOG.md b/CHANGELOG.md index 126b19e028..8049dcca1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,238 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.9.1] - 2026-04-21 + +### Fixed + +- 🐛 **Missing `aiosqlite` dependency.** Fixed a startup crash (`ModuleNotFoundError: No module named 'aiosqlite'`) when installing Open WebUI via `pip` or `uv` by adding the missing `aiosqlite` package to `pyproject.toml`. The dependency was listed in `requirements.txt` but not in the published package metadata, so it was not installed automatically. [#23916](https://github.com/open-webui/open-webui/issues/23916) +- 🐛 **Missing `asyncpg` dependency.** Added the missing `asyncpg` package to `pyproject.toml` to prevent the same startup crash for PostgreSQL users. Like `aiosqlite`, it was present in `requirements.txt` but absent from the published package dependencies. + +## [0.9.0] - 2026-04-20 + +### Added + +- 🖥️ **Official Open WebUI Desktop App.** Open WebUI is now available as a native desktop app for Mac, Windows, and Linux. No Docker, no terminal, no setup. Runs Open WebUI locally without any server setup, or connects to your existing remote Open WebUI instances. Switch between multiple servers instantly from the sidebar. Comes with a system-wide floating chat bar (Shift+Cmd+I on macOS, Shift+Ctrl+I on Windows/Linux), system-wide push-to-talk, offline support after first launch, automatic updates, and zero telemetry. [#8262](https://github.com/open-webui/open-webui/issues/8262), [Desktop](https://github.com/open-webui/desktop) +- 🤖 **Scheduled chat automations.** You can now schedule the AI to run tasks automatically on a recurring basis: daily digests, periodic reports, anything you'd otherwise need to remember to ask for. Create and manage automations from the Automations page or directly in chat, with full run history and manual trigger controls. [#23303](https://github.com/open-webui/open-webui/pull/23303), [Commit](https://github.com/open-webui/open-webui/commit/5a2ff8b2e5b6f55a20f7ed491f818490eb535ea7), [Commit](https://github.com/open-webui/open-webui/commit/d30a0531d4add045c21a2368d6321a9b1906865f), [Commit](https://github.com/open-webui/open-webui/commit/bae5ff938ac88a3a647cc31ca8db1101015ae18b), [Commit](https://github.com/open-webui/open-webui/commit/588b81eedaacbfd7394b707ae1600d9fb729b809..674695918e5e3e1811314ce2a082c5bbb42d76b2) +- 🧰 **Automation tools in chat.** Built-in chat tools can now create, update, list, pause, and delete scheduled automations directly in conversation when automation access is enabled. [Commit](https://github.com/open-webui/open-webui/commit/588b81eedaacbfd7394b707ae1600d9fb729b809..674695918e5e3e1811314ce2a082c5bbb42d76b2) +- ⏱️ **Automation scheduling limits.** Administrators can now set "AUTOMATION_MAX_COUNT" and "AUTOMATION_MIN_INTERVAL" to limit how many automations each non-admin user can create and prevent overly frequent schedules that could overload the system. [Commit](https://github.com/open-webui/open-webui/commit/406251c2f358ffabce4d631c98c6f2c879feae5c) +- 📋 **Task management tool.** AI models can now create, update, and track tasks within a chat conversation, breaking down complex requests into manageable steps with real-time status updates. [Commit](https://github.com/open-webui/open-webui/commit/bcb71bb5206ac01d97a39fde8ecf0e0541dde636) +- 🗓️ **Calendar workspace and event management.** Open WebUI now has a full Calendar workspace. Create and manage events, set up recurring schedules, get reminders via in-app toasts or browser notifications, and see your scheduled automations alongside your calendar. [#23880](https://github.com/open-webui/open-webui/pull/23880) +- 🔔 **Calendar reminders and alerts.** Calendar events now support reminder options from no alert up to one hour before start time, with upcoming alerts delivered through in-app toasts, browser notifications, and optional webhooks while avoiding duplicate sends. [Commit](https://github.com/open-webui/open-webui/commit/e5b5a174265d6710e986f6534ee7e3b2923233be) +- ⚙️ **Scheduler reminder configuration.** Administrators can now configure calendar reminder processing with "SCHEDULER_POLL_INTERVAL" and "CALENDAR_ALERT_LOOKAHEAD_MINUTES", while existing "AUTOMATION_POLL_INTERVAL" setups continue to work as a legacy fallback. [Commit](https://github.com/open-webui/open-webui/commit/e5b5a174265d6710e986f6534ee7e3b2923233be) +- ☁️ **Azure responses support.** Azure OpenAI connections now support the newer "/openai/v1" format, enabling chat, responses, and proxy calls to work correctly with that endpoint style. [#23484](https://github.com/open-webui/open-webui/pull/23484) +- 🤖 **Ollama responses support.** The Ollama proxy now supports the Responses API, letting clients use "/v1/responses" directly with Ollama-hosted models through Open WebUI. [#23483](https://github.com/open-webui/open-webui/pull/23483) +- 🧩 **Responses tool output rendering.** Built-in tool outputs in Responses API flows now render more consistently so downstream chat output is easier to interpret. [Commit](https://github.com/open-webui/open-webui/commit/e695d854f2d11fada84d5fbec8d3edea4e468e19), [#23482](https://github.com/open-webui/open-webui/pull/23482) +- 🔎 **Responses citation visibility.** Responses API flows now emit citation sources more consistently, making linked references easier to preserve and display in chat output. [Commit](https://github.com/open-webui/open-webui/commit/e695d854f2d11fada84d5fbec8d3edea4e468e19), [#23774](https://github.com/open-webui/open-webui/issues/23774) +- 📎 **Attach previously uploaded files.** The chat input menu now includes a Files tab for browsing and attaching previously uploaded files, eliminating the need to re-upload files you have already shared. [Commit](https://github.com/open-webui/open-webui/commit/edb8971c7dbd974322c3207c4655ff66479c3ee2) +- 🧷 **Default model terminal selection.** Workspace model editors can now preselect an Open Terminal connection, so new chats automatically start with the model’s configured terminal ready to use. [Commit](https://github.com/open-webui/open-webui/commit/47d413ce7b2a006a8126f4a9055b13e5fcb33a1d), [#23605](https://github.com/open-webui/open-webui/issues/23605) +- 🎙️ **Mistral TTS support.** Mistral can now be used as a text-to-speech provider, with admin settings for the API key, base URL, voices, and model selection. [Commit](https://github.com/open-webui/open-webui/commit/4cee67e2be0c80a0b501073ea49a80d13efd1c41) +- 🎧 **STT preprocessing bypass option.** Administrators can now enable "AUDIO_STT_SKIP_PREPROCESSING" to send audio files directly to the speech-to-text backend, reducing memory and CPU consumption during large uploads for better transcription performance and stability on constrained deployments. [#23661](https://github.com/open-webui/open-webui/pull/23661) +- 🗑️ **Admin model deletion.** Administrators can now delete Ollama models directly from the model selector menu, making it easier to clean up unused or unwanted models. [Commit](https://github.com/open-webui/open-webui/commit/2388dd7dc3530b5dd5419c5d0bb1bcdcb7544099) +- 🔌 **Backend outlet filters for local and persisted chats.** Pipeline and function outlet filters now run reliably in backend completion flows for persisted chats and temporary local chats. [#3237](https://github.com/open-webui/open-webui/issues/3237), [Commit](https://github.com/open-webui/open-webui/commit/cf4218e688def6f11d195aeda6665ae5b5376b67) +- 🎨 **Emoji shortcode support.** Typing a colon in the chat input now opens an emoji suggestion menu, making it easier to insert emojis using shortcodes like :wave:. [Commit](https://github.com/open-webui/open-webui/commit/2040095050056d01c61aa597c5010445449a42c7) +- 📌 **Recently used emojis.** The emoji picker now shows your most recently used emojis at the top, making it faster to find emojis you use often. [Commit](https://github.com/open-webui/open-webui/commit/64da99a32218171d41b3af5acc14783de8dbdf49) +- 👆 **Swipe to reply on mobile.** Swiping right on a message now triggers a reply, making it easier to respond on touch devices with a natural gesture. [Commit](https://github.com/open-webui/open-webui/commit/012ce95f27d57bea8911bd63bfb923443c5797ae) +- 📱 **Screen-awake voice recording.** Voice recording now keeps the screen awake during active dictation and safely re-acquires wake lock after visibility changes, helping prevent long transcriptions from being cut off on mobile devices. [#23145](https://github.com/open-webui/open-webui/issues/23145) +- 🔔 **Unread chat indicators.** Sidebar chats now show unread status and are marked as read when opened, making it easier to spot conversations with new activity. [Commit](https://github.com/open-webui/open-webui/commit/0638b9f56ce1ba8a496d0e84da2e7fa178b01a3f) +- 🔌 **WebSocket reconnect status feedback.** Open WebUI now warns when the real-time connection drops and confirms when it reconnects, while avoiding a reconnect message on the initial page load. [Commit](https://github.com/open-webui/open-webui/commit/1824e69a70e756cfcf543a9fbe4b0780d9b57292) +- 📍 **Pinned notes in sidebar.** Notes can now be pinned to the sidebar for quick access, and you can also create a new note directly from the pinned notes section. [Commit](https://github.com/open-webui/open-webui/commit/ecd74f220c7dd671d5705189a3f4493a3868c8bf), [Commit](https://github.com/open-webui/open-webui/commit/f1be85d997439b49fc143d2bcd2dc710f44446c8) +- 🗂️ **Model selector focus.** The model selector now resets its search only when it opens, making the popup feel more predictable while still focusing the search field automatically. [Commit](https://github.com/open-webui/open-webui/commit/b89019a8e1f96e01dc8e19a81ef8fb4f4eae3eef) +- 🗂️ **Model selector layout.** The model selector now behaves more predictably as a custom popup, and the completions playground uses a simpler model picker for easier selection. [Commit](https://github.com/open-webui/open-webui/commit/c40ea7f29d34fa9535cdf9ffe599f4429ff3f455) +- 🎚️ **Active filter valve shortcut.** Active filter badges now expose valve configuration directly in the chat input area, so filter tuning is faster during conversations. [Commit](https://github.com/open-webui/open-webui/commit/3c22afc5a67404047797921185aca984b10b45cd), [#23811](https://github.com/open-webui/open-webui/issues/23811), [#23813](https://github.com/open-webui/open-webui/pull/23813) +- 🎨 **Theme updates.** Other windows can now update the app theme directly, keeping the interface in sync when theme changes are triggered externally. [Commit](https://github.com/open-webui/open-webui/commit/9f1b279e88bd22dfff4d2531209536dea6a2f65e) +- 🚀 **Async performance and responsiveness improvements.** The core backend database and request paths now run asynchronously across the application, massively improving responsiveness and performance under concurrent load and reducing request blocking during heavy activity. [Commit](https://github.com/open-webui/open-webui/commit/27169124f220e5cea21c88601c731c3749496ab0), [Commit](https://github.com/open-webui/open-webui/commit/8936721414a17832852a90f3ee592af5a8b7232d) +- ⚡ **Drawer performance and memory optimization.** Drawer interactions now stay smoother over long sessions by removing stale keyboard listeners on teardown, which reduces memory growth and avoids accumulated event handling overhead. [#23724](https://github.com/open-webui/open-webui/pull/23724#issuecomment-4245840810) +- 🚀 **Chat history memory culling.** Long conversations now stay responsive no matter how many messages they contain. Off-screen messages are unloaded automatically and reloaded as you scroll, keeping memory usage low and the UI smooth on both desktop and mobile. [#23067](https://github.com/open-webui/open-webui/issues/23067), [Commit](https://github.com/open-webui/open-webui/commit/026903399be73ac4b6c226647110e5662d043a50), [Commit](https://github.com/open-webui/open-webui/commit/9dccd29c94875e6f0ac373c5802cb183296e47ff) +- 🧵 **Async file and knowledge processing performance.** File processing, knowledge reindexing, and channel message helper paths now consistently await async operations, preventing skipped processing steps and improving reliability and performance of indexing and tool responses. [Commit](https://github.com/open-webui/open-webui/commit/de27a121511a31606f250ba4033490797216a0eb) +- 🚀 **Persistent chat payload efficiency.** Persisted chats now use server-side history loading instead of repeatedly resending full message payloads, improving multimodal performance and reducing stale-history overwrite risk across devices. [#19064](https://github.com/open-webui/open-webui/issues/19064), [Commit](https://github.com/open-webui/open-webui/commit/18fe17127a7175579506e7456d3e5aba201371e6), [Commit](https://github.com/open-webui/open-webui/commit/cf4218e688def6f11d195aeda6665ae5b5376b67) +- 🧵 **Non-blocking file storage operations.** Uploading, reading, transcribing, and deleting files now offloads storage I/O to background threads, keeping the application responsive during file-heavy workflows. [Commit](https://github.com/open-webui/open-webui/commit/4866bec0f238198a721c952fe18dd04ba643be33) +- 🏎️ **Streaming response performance.** Streaming responses now process each output line in a single step instead of two separate yields, reducing async overhead and improving responsiveness during long-running generations. [#23266](https://github.com/open-webui/open-webui/pull/23266) +- 🔎 **Faster mention parsing.** Chat text with HTML-like content, file paths, or tool output now parses mentions more efficiently, which helps keep typing and rendering responsive in messages that contain many '<' characters. [#23551](https://github.com/open-webui/open-webui/pull/23551) +- 🧪 **Code block rendering performance.** Code blocks now reuse a shared HTML unescape helper, reducing extra browser work when displaying encoded output in chat. [#23553](https://github.com/open-webui/open-webui/pull/23553) +- 🚀 **Inline code rendering performance.** Inline code tokens in streaming responses now fade in with a lightweight CSS animation, making chat output feel smoother while reducing interface overhead during rapid token updates. [#23258](https://github.com/open-webui/open-webui/pull/23258) +- 🎞️ **Streaming text token animation performance.** Streaming text tokens now use a lightweight CSS intro animation, making output feel smoother while reducing transition overhead and preventing tokens from fading out when generation completes. [#23257](https://github.com/open-webui/open-webui/pull/23257) +- 🎯 **Template token scan optimization.** Streaming responses now skip unnecessary token-replacement processing when no template markers are present, reducing per-update overhead and keeping chat output smoother during rapid generation. [#23161](https://github.com/open-webui/open-webui/pull/23161) +- 🔬 **Chinese text processing guard performance.** Streaming responses without Chinese characters now skip unnecessary Chinese-format processing checks, reducing per-update overhead and keeping output smoother during rapid generation. [#23162](https://github.com/open-webui/open-webui/pull/23162) +- 🧠 **HTML entity decode performance.** Streaming text decoding now avoids repeated document parsing for HTML entity handling, reducing memory churn and improving responsiveness in token-heavy chat output. [#23165](https://github.com/open-webui/open-webui/pull/23165) +- 🏷️ **Chat title update performance.** Chat title updates now run in a single database operation instead of multiple round trips, improving responsiveness and reducing overhead when titles are generated or renamed. [#23214](https://github.com/open-webui/open-webui/pull/23214) +- 📂 **Faster chat list queries performance.** Chat and folder lists now load more efficiently by fetching only the fields needed for sidebar views, improving responsiveness when browsing large conversation histories. [Commit](https://github.com/open-webui/open-webui/commit/0e5696de74cc0ba55b24cfc3d02efa83f08d7d3f) +- 📈 **Sidebar memory optimization.** Sidebar chat items now use shared drag-preview resources and safer listener cleanup, reducing memory growth and keeping large chat lists more responsive during long sessions. [#23209](https://github.com/open-webui/open-webui/pull/23209) +- 🧠 **Image viewer memory optimization.** Viewing images and SVGs now uses significantly less memory and performs faster, keeping the application snappy and responsive even when browsing through many media files during extended sessions. [#23236](https://github.com/open-webui/open-webui/pull/23236) +- 📡 **Optimized user activity tracking performance.** User activity updates now use a single database query instead of multiple operations, improving response times across all authenticated requests. [#23215](https://github.com/open-webui/open-webui/pull/23215) +- 👥 **Faster channel thread author loading.** Channel thread responses now load author details in a single batch query, reducing database overhead and improving responsiveness in threads with many participants. [#23795](https://github.com/open-webui/open-webui/pull/23795) +- 💨 **Optimized shared chat deletion.** Deleting shared chats by user is now faster and more memory-efficient by only loading necessary data. [#23216](https://github.com/open-webui/open-webui/pull/23216) +- 🗃️ **Faster chat tag loading.** Chat tag lookups now load only the metadata needed instead of full chat payloads, improving responsiveness for chats with large histories. [#23798](https://github.com/open-webui/open-webui/pull/23798) +- 📎 **Faster chat file deduplication.** Attaching files to chat messages now checks duplicates more efficiently, reducing overhead when handling larger file lists. [#23800](https://github.com/open-webui/open-webui/pull/23800) +- 📈 **Faster message diff checks.** Chat message and status updates now compare content more efficiently during streaming, making active conversations feel smoother and more responsive. [#23370](https://github.com/open-webui/open-webui/pull/23370) +- ⚖️ **Faster deep equality checks.** Chat message updates, model selection, note editing, code block refreshes, and rich text state comparisons now use deep equality checks that reduce unnecessary UI work and improve responsiveness in active sessions. [#23845](https://github.com/open-webui/open-webui/pull/23845) +- 🏃 **Faster knowledge access updates.** Updating access grants for knowledge items now completes with less backend overhead, making permission changes apply more quickly. [#23799](https://github.com/open-webui/open-webui/pull/23799) +- 🧹 **Mermaid render cleanup performance.** Mermaid diagrams now always clean up temporary render elements after failures, reducing DOM buildup and keeping repeated rendering more stable over time. [#23727](https://github.com/open-webui/open-webui/pull/23727) +- 🖼️ **Model image lookup efficiency.** Model profile image requests now reuse the current request database session, reducing per-request overhead and improving response efficiency. [#23796](https://github.com/open-webui/open-webui/pull/23796) +- 👤 **User endpoint query reduction.** Session-based user settings and status endpoints now avoid redundant user re-fetches, reducing unnecessary database load while preserving behavior. [#23794](https://github.com/open-webui/open-webui/pull/23794) +- 🚦 **Faster startup performance.** Open WebUI now checks for Torch MPS support only on macOS, avoiding unnecessary startup work on other platforms. [#23438](https://github.com/open-webui/open-webui/pull/23438) +- 🛡️ **Redis timeout consistency.** Redis connections now honor the "REDIS_SOCKET_CONNECT_TIMEOUT" setting across standard and cluster setups, helping workers fail faster when Redis is unreachable. [#23572](https://github.com/open-webui/open-webui/pull/23572) +- 🧰 **AIOHTTP pool controls.** Administrators can now tune shared outbound HTTP connection behavior with "AIOHTTP_POOL_CONNECTIONS", "AIOHTTP_POOL_CONNECTIONS_PER_HOST", and "AIOHTTP_POOL_DNS_TTL" for better control under high concurrency. [Commit](https://github.com/open-webui/open-webui/commit/c47dd7b7717c4186e0f0549ca3c8cb4d9bb38135) +- ⏱️ **MCP tool server timeout configuration.** Administrators can now configure request timeouts for MCP tool server connections via the AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER environment variable. [Commit](https://github.com/open-webui/open-webui/commit/10b4b86ada93cd62d994c3179ff14dfd1a6e56f0) +- 🎫 **Static OAuth tool authentication.** Tool server authentication now works reliably for both "oauth_2.1" and "oauth_2.1_static" connection types, so OAuth-backed tool access is correctly detected and forwarded during chat requests. [Commit](https://github.com/open-webui/open-webui/commit/60676bfdcfbce1a69b3e97f2013f0cfd63371737) +- 🗄️ **Configurable storage local cache.** Administrators can now disable persistent local caching for cloud-backed uploads with the "STORAGE_LOCAL_CACHE" setting, reducing local disk usage by cleaning temporary upload copies after processing. [Commit](https://github.com/open-webui/open-webui/commit/8172c7e3d56918d1372be06b9369b58a3a88f6b1) +- 🚪 **Back-channel logout.** OpenID Connect providers can now trigger centralized logout through the "ENABLE_OAUTH_BACKCHANNEL_LOGOUT" setting, helping administrators invalidate user sessions more reliably across connected devices. [Commit](https://github.com/open-webui/open-webui/commit/0dd9f462ffb2f160bc4aebad182047f41874d250) +- 🛡️ **Expanded security header controls.** Administrators can now configure additional browser security headers, including "CONTENT_SECURITY_POLICY_REPORT_ONLY", "CROSS_ORIGIN_EMBEDDER_POLICY", "CROSS_ORIGIN_OPENER_POLICY", and "CROSS_ORIGIN_RESOURCE_POLICY", for stricter and more flexible deployment hardening. [Commit](https://github.com/open-webui/open-webui/commit/f246a66810fa4995d9494da3599c0fb297fb0213) +- 🖼️ **Image MIME fallback option.** Administrators can now enable "ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK" so image-to-base64 conversion can still detect common image types by file extension when MIME metadata is missing, improving compatibility on minimal container images and older file records. [Commit](https://github.com/open-webui/open-webui/commit/5127354b3eb4eaa71bc4ad68da69729e2196e7a4) +- 🛡️ **Public sharing permissions.** Public channels, models, notes, prompts, and tools now respect allowed access grants more consistently, helping administrators control who can share content more safely. [Commit](https://github.com/open-webui/open-webui/commit/9d3e0637c86292b8b92e7607097a83f1075d7cd8) +- 🆔 **Skill lookup by ID.** Skill instructions now include each skill’s ID, and the skill viewer now finds skills by ID in a case-insensitive way so attached skills are identified more reliably in chats. [Commit](https://github.com/open-webui/open-webui/commit/65ee771fd0d62d785ecbcf189e3f5b63858c11e6) +- 🏷️ **Source context metadata.** Retrieval source context now includes each source’s resource type and resource ID metadata, helping downstream model workflows preserve richer source identity during processing. [Commit](https://github.com/open-webui/open-webui/commit/c3c8c605d76a3b0ee067307f9cef6d081658e287) +- 🗂️ **Feedback filtering.** Administrators can now filter feedback history by model and export only the feedback they need. [Commit](https://github.com/open-webui/open-webui/commit/60e4d7517463690b3a87de38babc9ac561897c61) +- 📤 **CSV feedback export.** Feedback history can now be exported as either JSON or CSV, making it easier to analyze feedback in spreadsheet tools. [Commit](https://github.com/open-webui/open-webui/commit/342582676a5212bf196a69d11825cb407992f257) +- 📝 **Optional GET audit logging.** Administrators can now enable auditing for GET requests with the "ENABLE_AUDIT_GET_REQUESTS" setting when they need fuller request visibility. [Commit](https://github.com/open-webui/open-webui/commit/5ee791d5d28f236755243cb7d16d8737bb69ce36) +- 🕒 **Model access updates.** Changing a model’s access grants now updates its timestamp, so recently modified models stay easier to find and sort correctly. [Commit](https://github.com/open-webui/open-webui/commit/53eadb7df7281f5661cbe22c8b26b5aedaba3083) +- 💬 **Queued message handling.** Queued chat messages now send more reliably without advancing the queue too early, keeping follow-up prompts in the intended order. [Commit](https://github.com/open-webui/open-webui/commit/730e52a431d157dc62d72260668087437f1d52f4) +- 🔒 **Rendered content safety.** Placeholder descriptions and the pending account notice now render markdown with safer sanitization ordering, reducing the risk of unsafe HTML appearing in these views. [Commit](https://github.com/open-webui/open-webui/commit/253f416de3f2d3a939a6feef2a56413fd61cc70b) +- 🛡️ **Safer placeholder rendering.** Chat placeholder descriptions and the pending account notice now sanitize rendered markdown more consistently, reducing the risk of unsafe content being shown in these views. [Commit](https://github.com/open-webui/open-webui/commit/ae0316a30e01a2e5ff3f9d2f9f759c1cd6410f34) +- 🧮 **Usage analytics accuracy.** Token usage is now normalized before chat messages are saved, so model and user usage reports stay accurate across OpenAI-compatible providers. [Commit](https://github.com/open-webui/open-webui/commit/4dea4fdf54e00ebaba8e3178128bf8709453d2a2) +- 🧩 **Richer Anthropic tool results.** Anthropic-compatible tool calls now preserve more tool result content types, including images and structured search or document outputs, so models can use fuller tool context instead of receiving only plain text fragments. [#23188](https://github.com/open-webui/open-webui/issues/23188), [Commit](https://github.com/open-webui/open-webui/commit/40f5b3d135190dc9a2d8e94dbb1b2cbcbd829132) +- 🖼️ **ComfyUI request reliability.** ComfyUI image generation and editing now use shared async connections with consistent SSL handling, making image uploads and workflow runs more reliable under concurrent load. [Commit](https://github.com/open-webui/open-webui/commit/5944eda0ff25a284f7157252683bccede741cbe7) +- 🎛️ **Reranking batch size control.** Administrators can now set "RAG_RERANKING_BATCH_SIZE" in Documents settings to control reranking workload size, helping balance retrieval speed and resource usage for their deployment. [Commit](https://github.com/open-webui/open-webui/commit/4d2f18981051205016bd24d39521e25a33581225) +- 🔗 **Shared chat access controls.** You can now control who has access to a shared chat by granting access to specific users or groups, instead of sharing with anyone who has the link. +- 🔄 **General improvements.** Various improvements were implemented across the application to enhance performance, stability, and security. +- 🌐 **Translation updates.** Translations for Irish, Catalan, German, Simplified Chinese, Hindi, and Portuguese (Brazil) were enhanced and expanded. + +### Fixed + +- 🛡️ **Model description XSS protection.** Model descriptions shown in chat placeholders are now sanitized before rendering, preventing malicious links from executing scripts and helping protect user sessions from takeover. [#23621](https://github.com/open-webui/open-webui/pull/23621) +- 🧠 **Memory search filtering.** Memory search now correctly filters by the query text instead of returning unrelated results. [Commit](https://github.com/open-webui/open-webui/commit/43e5905c133049036353978704b0abd179716749), [#23826](https://github.com/open-webui/open-webui/issues/23826) +- 📊 **Shared chat analytics consistency.** Usage and message-count analytics now count assistant activity consistently across regular and shared chats, improving accuracy in model, user, chat, and time-based reporting views. [Commit](https://github.com/open-webui/open-webui/commit/e29d145a1cff23122de16123a4cfda1b84abffbb) +- 🧭 **Safer in-flight chat navigation.** Sending a message no longer overwrites your active chat or causes duplicate background notifications when you switch conversations before a response finishes. [Commit](https://github.com/open-webui/open-webui/commit/dc6df52a917b49fa1264ac81a8cc74603f6155b3) +- 🗣️ **Pipeline error detail visibility.** Pipeline inlet and outlet failures now preserve and surface provider error details more reliably in chat error messages, making troubleshooting failed requests much clearer. [Commit](https://github.com/open-webui/open-webui/commit/d5e69f182cd7a6371ab25248f6432b277f83ef23) +- 📨 **Shared chat event routing.** Message update and send events now target the chat owner’s event channel, so shared chats receive the correct real-time updates instead of routing events to the acting user. [Commit](https://github.com/open-webui/open-webui/commit/47329b5032ba29716a7e7e973b07c6d9894968e0) +- 🔐 **Consistent outbound SSL handling.** External requests for tools, functions, terminals, webhooks, retrieval loaders, audio provider discovery, and OpenAI-compatible embedding calls now consistently apply the configured SSL client setting, improving reliability for deployments that require custom certificate or verification behavior. [Commit](https://github.com/open-webui/open-webui/commit/fd25152076ea7c310e42c9bacc5cd2b544eeae48), [Commit](https://github.com/open-webui/open-webui/commit/56c5bc1d3487020ab886d3332aacc1644c1d6123) +- 🖼️ **Image SSL setting support.** Image generation now respects the configured SSL session setting, preventing avoidable connection failures in strict certificate environments. [Commit](https://github.com/open-webui/open-webui/commit/128cf41fcedf2638fc8a6acd850d8b0409be1c4e), [#23777](https://github.com/open-webui/open-webui/issues/23777) +- 🗂️ **Folder ownership assignment hardening.** Folder create and update inputs now reject unexpected extra fields, preventing clients from overriding protected values like ownership through mass-assignment payloads. [#23648](https://github.com/open-webui/open-webui/pull/23648) +- 🔐 **Knowledge file deletion ownership checks.** Collaborators with knowledge base write access can no longer permanently delete files they do not own, preventing unintended file removal across other linked chats and knowledge bases. [Commit](https://github.com/open-webui/open-webui/commit/914ccf07ef158afe5588b97ed42778c93c439938), [#23636](https://github.com/open-webui/open-webui/pull/23636#issuecomment-4232439454) +- 🗑️ **Knowledge deletion reliability.** Deleting a knowledge base by ID now completes reliably without unexpected failures. [Commit](https://github.com/open-webui/open-webui/commit/7e453de4f7794ff386e285aa5951b94e926ec273), [#23776](https://github.com/open-webui/open-webui/issues/23776), [#23814](https://github.com/open-webui/open-webui/pull/23814) +- 🔐 **OAuth 2.1 PKCE enforcement.** OAuth 2.1 providers now default to S256 PKCE even when discovery metadata omits supported challenge methods, preventing login failures with providers that require PKCE by default. [#23667](https://github.com/open-webui/open-webui/issues/23667), [Commit](https://github.com/open-webui/open-webui/commit/050c4b97a95addc5eaeef86ba00631673a90dec4) +- 🔐 **Static OAuth scope handling.** Static OAuth credential flows now prioritize administrator-defined scopes and handle OAuth 2.1 static flow behavior more reliably. [Commit](https://github.com/open-webui/open-webui/commit/349ea4ea9e577f2cbfb4917ef5f52e5ac53c5b70), [#23668](https://github.com/open-webui/open-webui/issues/23668), [#23696](https://github.com/open-webui/open-webui/pull/23696), [#23783](https://github.com/open-webui/open-webui/pull/23783) +- 🔐 **Static OAuth tool registration reliability.** Static OAuth tool server registration now resolves and uses saved admin credentials more reliably, preventing registration failures when valid client credentials are provided. [#23670](https://github.com/open-webui/open-webui/issues/23670), [Commit](https://github.com/open-webui/open-webui/commit/2943955c529138c0e530fd07b6333a0052e3684e), [Commit](https://github.com/open-webui/open-webui/commit/c767bcaa739f76b1a4337dfd9d6be47adb504825) +- ⏳ **OAuth token expiry fallback.** OAuth sessions now always store a safe expiry value even when providers omit "expires_in" or "expires_at", so token refresh checks continue working and tool calls are less likely to fail later with unexpected authorization errors. [#23669](https://github.com/open-webui/open-webui/issues/23669), [Commit](https://github.com/open-webui/open-webui/commit/31406caa795173a59d5843d3601b891bf617cbaa) +- 🔑 **Anthropic x-api-key model access.** Anthropic-compatible clients can now authenticate with the "x-api-key" header across all relevant API routes, so model listing requests like GET "/api/v1/models" no longer fail with unauthorized errors. [#23319](https://github.com/open-webui/open-webui/issues/23319), [Commit](https://github.com/open-webui/open-webui/commit/611fe0c8a938539b73b559e84964f40c30bf436d) +- 🔑 **SSO password option visibility.** Account settings now hide password change controls when password-change access is disabled, avoiding misleading password options for SSO-focused setups. [#15292](https://github.com/open-webui/open-webui/issues/15292), [Commit](https://github.com/open-webui/open-webui/commit/cced77b584d6ea46c58fecddb2b3dd5e955c8417) +- 🔑 **Open Terminal MCP authentication.** Open Terminal MCP tool calls now include the configured API key when calling internal routes, preventing unauthorized errors for commands like file reads and command execution. [#106](https://github.com/open-webui/open-terminal/pull/106) +- 🧯 **Provider error freeze recovery.** Task-based chat requests now surface provider HTTP errors through normal failure handling, so content-filter and other upstream 4xx responses no longer leave chats stuck in a perpetual loading state. [#23663](https://github.com/open-webui/open-webui/issues/23663), [Commit](https://github.com/open-webui/open-webui/commit/96265cf042c8ab97dbec5d0efcce8010d0cd76e5) +- 🔄 **Immediate outlet filter updates.** Assistant messages modified by outlet filters now appear correctly as soon as streaming completes, without requiring a page refresh. [#23829](https://github.com/open-webui/open-webui/pull/23829) +- 🌊 **Middleware cancellation reliability.** Long-running requests now complete more reliably by preventing middleware-level cancellations from interrupting in-flight database and embedding work, reducing unexpected failures and noisy error logs when connections close early. [#23709](https://github.com/open-webui/open-webui/pull/23709) +- 🚦 **Async vector search responsiveness.** File processing, memory updates, and knowledge retrieval no longer block the server event loop during vector database operations, so other chats and requests stay responsive while indexing or search is running. [#23706](https://github.com/open-webui/open-webui/pull/23706) +- 🗒️ **Notes chat llama.cpp compatibility.** Notes AI chat no longer sends empty assistant prefill messages that can conflict with reasoning-enabled llama.cpp responses, preventing immediate 400 errors in Notes conversations. [Commit](https://github.com/open-webui/open-webui/commit/fd93bd3414a1725219e14561bc5640b62f9fd4a1), [#23703](https://github.com/open-webui/open-webui/issues/23703#issuecomment-4243907629) +- 🧩 **Ollama thinking field preservation.** Messages modified by filters now keep the Ollama "thinking" field when sent to the model, so reasoning-aware workflows and custom filter-based passthrough setups work reliably. [Commit](https://github.com/open-webui/open-webui/commit/8bd23b91459914eb7df5b5a66567d3544e0da168), [#22508](https://github.com/open-webui/open-webui/issues/22508) +- 🧾 **Reasoning content preservation.** Assistant tool-call messages now retain reasoning content across turns, improving reliability for reasoning-heavy model workflows. [Commit](https://github.com/open-webui/open-webui/commit/3dd8255816898467246c81cba3c9bc48bc18d86d), [#23175](https://github.com/open-webui/open-webui/issues/23175), [#23742](https://github.com/open-webui/open-webui/pull/23742) +- 🧭 **Background task scoping for new chats.** Chat title and auto-tag generation now run only for the first message of a new conversation and only once in multi-model responses, preventing duplicate or incorrectly triggered background tasks in follow-up flows. [Commit](https://github.com/open-webui/open-webui/commit/f102060a6d85db4acd3d0bf5c25e976f36cd5533..a4ed16999eec9a654a37c2bb4c15ba5ecd1fa3b7) +- 📚 **Channel document context retention.** Channel conversations now preserve and load the correct stored message history so model responses can use uploaded and retrieved document context more reliably. [#23686](https://github.com/open-webui/open-webui/issues/23686), [Commit](https://github.com/open-webui/open-webui/commit/cf4218e688def6f11d195aeda6665ae5b5376b67), [Commit](https://github.com/open-webui/open-webui/commit/18fe17127a7175579506e7456d3e5aba201371e6) +- ⏳ **Interrupted response recovery.** Assistant placeholder messages now start as incomplete and recover more safely after interrupted generations, preventing silent empty replies after refreshes or dropped requests. [#23176](https://github.com/open-webui/open-webui/issues/23176), [Commit](https://github.com/open-webui/open-webui/commit/c8ef7b028931263e8773cb60a7111d80d9572d26), [Commit](https://github.com/open-webui/open-webui/commit/cf4218e688def6f11d195aeda6665ae5b5376b67) +- 🧰 **Large tool result rendering.** Tool call details now display large result payloads reliably in chat instead of intermittently showing empty output for bigger tool responses. [#18743](https://github.com/open-webui/open-webui/issues/18743), [Commit](https://github.com/open-webui/open-webui/commit/45e49d33e51f7720c00b564215484aff9b48b20c) +- 🧼 **Null-byte document sanitization.** PDF and other document ingests now sanitize null bytes and invalid surrogate characters before pgvector writes, preventing PostgreSQL upload failures and allowing affected files to index successfully. [#22992](https://github.com/open-webui/open-webui/issues/22992), [Commit](https://github.com/open-webui/open-webui/commit/8dba798cce9fb1efc5f6acc5f37b152662db78d7) +- 📝 **Knowledge text editor stability.** The Knowledge "Add Text Content" modal now uses a plain text editor, avoiding current rich text editor issues and keeping drafting behavior consistent with existing knowledge editing flows. [Commit](https://github.com/open-webui/open-webui/commit/cd55c3e21237e000c13c6f396bb95b261f3bda82) +- 🎤 **STT SSL setting consistency.** Speech and related outbound media requests now consistently use shared async HTTP sessions and honor the configured SSL verification setting, improving compatibility with self-signed deployments. [#23672](https://github.com/open-webui/open-webui/issues/23672), [Commit](https://github.com/open-webui/open-webui/commit/2ddcb30b9a519885422ba1f36cc3485a7d897bf8) +- 🎙️ **Mistral speech input format.** Mistral speech-to-text requests now use the correct chat-completions audio input format for better compatibility. [Commit](https://github.com/open-webui/open-webui/commit/34d569d564a8ef2702c647dbad83eac840b76b2e), [#23822](https://github.com/open-webui/open-webui/issues/23822) +- 🖼️ **Optional image size parameter.** Image generation no longer sends the "size" field when no size is configured, improving compatibility with providers that reject unsupported size arguments. [#23611](https://github.com/open-webui/open-webui/issues/23611), [Commit](https://github.com/open-webui/open-webui/commit/869cf9e848b741705dc058550fa1b3f70db47fe8) +- 🔎 **FireCrawl timeout reliability.** FireCrawl web loading now uses direct scrape requests and improved timeout handling for single-URL fetches, reducing empty results and premature timeout failures with local FireCrawl setups. [#23411](https://github.com/open-webui/open-webui/issues/23411), [Commit](https://github.com/open-webui/open-webui/commit/9c64d84ad90804bf7d891e4a5097c03c4d7044c3) +- 🖱️ **Custom action icon drag prevention.** Custom user-added action icons in chat responses are no longer accidentally draggable, so clicks and hover interactions behave consistently with built-in action icons. [#23412](https://github.com/open-webui/open-webui/pull/23412) +- 🖼️ **Image URL conversion reliability.** Sending image URLs to AI models no longer fails with "cannot pickle 'coroutine' object" errors, so image inputs now convert to base64 reliably during request processing. [#23685](https://github.com/open-webui/open-webui/pull/23685#issuecomment-4240424635) +- 📂 **Channel input menu dismissal.** In Workspace Channels, the message input dropdown now closes immediately after selecting "Upload Files" or "Capture", matching normal chat input behavior and preventing the menu from staying open unnecessarily. [#23684](https://github.com/open-webui/open-webui/pull/23684) +- 📋 **Clipboard copy scroll stability.** Copying content with the fallback clipboard method no longer triggers unwanted page scrolling during focus, keeping your current reading position stable. [Commit](https://github.com/open-webui/open-webui/commit/fc98000aa8d439bbff21a70370f5e962bf23f4bc) +- 🖼️ **Profile image URL validation.** Profile saves now accept valid Open WebUI profile-image paths, trusted external HTTP(S) avatar URLs, and safe raster data-image formats while rejecting unsafe URL patterns that could be abused. [#23389](https://github.com/open-webui/open-webui/pull/23389) +- 👤 **Partial user profile updates.** User update API requests can now modify only the fields you provide, so administrators no longer need to resubmit unchanged name, email, and profile image values when changing a single setting like role. [#23424](https://github.com/open-webui/open-webui/issues/23424), [Commit](https://github.com/open-webui/open-webui/commit/3c2c611ba91d794a1e73134ec41b0de2b3927677) +- 🚨 **Provider SSE error visibility.** Provider failures returned with streaming content types are now surfaced as proper API errors and logged clearly, so issues like context-window limits no longer fail silently during chat generation. [#23379](https://github.com/open-webui/open-webui/pull/23379) +- 🧵 **Queued prompt race prevention.** Chat request queues now prevent overlapping processing for the same chat, avoiding duplicate queue handling when multiple queue-processing triggers fire close together. [#23181](https://github.com/open-webui/open-webui/issues/23181), [Commit](https://github.com/open-webui/open-webui/commit/e10a00132eed54a0108fb6ac120e8229deef3656) +- 🛑 **Cancellation event delivery reliability.** Cancelled chat processing now safely emits task-cancel and error events only when an event emitter is available, while provider HTTP errors now also route through task-cancel handling so chats recover from blocked-loading states more reliably. [#23663](https://github.com/open-webui/open-webui/issues/23663), [Commit](https://github.com/open-webui/open-webui/commit/51765b619c8584b042af68c3a5c87525a105ccd8), [Commit](https://github.com/open-webui/open-webui/commit/96265cf042c8ab97dbec5d0efcce8010d0cd76e5) +- 🔑 **OIDC key-rotation recovery.** OIDC login now retries token authorization with refreshed provider signing keys after a bad-signature failure, so logins recover automatically after identity-provider key rotation without requiring a service restart. [#23582](https://github.com/open-webui/open-webui/issues/23582), [Commit](https://github.com/open-webui/open-webui/commit/facb194a07486e847f0725a0a839e99b5864d37b) +- 🌍 **Non-ASCII tag filtering.** Prompt and model tag filters now handle non-Latin tags more reliably across SQLite and PostgreSQL, so tags like Cyrillic values return the expected items in Workspace lists. [#23381](https://github.com/open-webui/open-webui/issues/23381), [#23427](https://github.com/open-webui/open-webui/pull/23427), [Commit](https://github.com/open-webui/open-webui/commit/57784706e4fee75dec67e20b0d89a97351ac6256) +- 🏷️ **Prompt tag query accuracy.** Prompt tag filtering now uses JSON-element-aware queries so tag-based lookups return the correct prompts. [Commit](https://github.com/open-webui/open-webui/commit/e7e752f8e74e7b01fe2e6cb56f06e99312e1afe7), [#23386](https://github.com/open-webui/open-webui/pull/23386) +- 🗃️ **SQLite async pool compatibility.** SQLite async database setup no longer forces an explicit queue pool class, avoiding pool configuration conflicts in SQLite deployments. [Commit](https://github.com/open-webui/open-webui/commit/26b8ca5b5eeb144fae3fe6eaeae826150d8af826) +- 🧠 **Knowledge embedding deadlock prevention.** Knowledge file processing now runs blocking vector-save work in a worker thread while keeping async status updates reliable, preventing file processing from stalling during long embedding operations. [Commit](https://github.com/open-webui/open-webui/commit/d4b90f93bda2413ec8f040e61959acdb7b242061), [Commit](https://github.com/open-webui/open-webui/commit/22cfb3c673cbfa4a6bce26fde8e2e2754ce4963b) +- 🤖 **Automation worker async DB handling.** Automation claiming and run recording now use async database sessions consistently, improving worker stability for scheduled automations. [Commit](https://github.com/open-webui/open-webui/commit/cb6e77be3ec6ce00dd1f5b9ce3a655e6f65bc5da) +- 🕒 **Automation timezone scheduling.** Scheduled automations now calculate each user’s next run time using that user’s saved timezone, preventing run drift caused by server-time fallback. [Commit](https://github.com/open-webui/open-webui/commit/a4d62253df55c6307112eb76a6bfa29a7f538e21) +- 🔎 **Notes search matching.** Notes search now handles multi-word and hyphenated queries more reliably, so relevant notes and snippets are easier to find from partial phrase searches. [Commit](https://github.com/open-webui/open-webui/commit/a35926261646f8897ba71da1572ed5dff802e3be) +- 📐 **Display math rendering.** Chat markdown now correctly recognizes and renders "$$...$$" expressions as display math, improving reliability for multiline and escaped KaTeX content while keeping malformed delimiters from disrupting message rendering. [#23526](https://github.com/open-webui/open-webui/issues/23526), [Commit](https://github.com/open-webui/open-webui/commit/15b89b9218b7d2c7239c579aa3d23c2892227ac6) +- 🚫 **LDAP empty-password rejection.** LDAP login now rejects empty or whitespace-only passwords before bind attempts, preventing unauthenticated simple-bind behavior from granting access on permissive LDAP server configurations. [#23633](https://github.com/open-webui/open-webui/pull/23633) +- 🌐 **IPv6 SSRF address blocking.** URL validation now uses standard IP address checks for both IPv4 and IPv6, preventing private, loopback, link-local, reserved, and mapped-address SSRF bypasses through IPv6 hostname resolution. [#23453](https://github.com/open-webui/open-webui/pull/23453) +- 🔒 **API key endpoint restriction bypass.** API key endpoint restrictions are now enforced regardless of whether the key is sent through Authorization headers, cookies, or "x-api-key", preventing bypass through alternate key transport paths. [#23637](https://github.com/open-webui/open-webui/pull/23637) +- 🔐 **Channel sharing permission enforcement.** Channel creation and updates now enforce allowed access grant rules for public sharing, preventing unauthorized wildcard sharing on group channels. [#23638](https://github.com/open-webui/open-webui/pull/23638) +- 🛑 **Socket role invalidation.** Socket sessions now disconnect automatically when a user is demoted or deleted, preventing stale admin privileges from persisting until reconnect. [#23642](https://github.com/open-webui/open-webui/pull/23642) +- 🛂 **Tool server access checks.** Tool listing now correctly awaits server access checks, preventing users from seeing server-backed tools they do not have permission to use. [Commit](https://github.com/open-webui/open-webui/commit/d40f31982be3eed37e55e3f67b1eea9a5dc8c525) +- 🛑 **Task endpoint access control.** Global task listing and direct task stop endpoints are now restricted to administrators, while regular users can stop only their own chat tasks through a scoped chat endpoint. [#23454](https://github.com/open-webui/open-webui/pull/23454) +- 🧱 **Redis cache key isolation.** Tool server and terminal server cache entries now include the Redis key prefix, preventing multiple Open WebUI instances that share one Redis database from overwriting each other’s cached connection data. [#23649](https://github.com/open-webui/open-webui/pull/23649) +- 🧠 **Client session leak prevention.** Outbound provider requests now use a shared session pool with safer response cleanup and shutdown handling, preventing aiohttp session buildup and reducing memory growth during heavy concurrent API traffic. [#23540](https://github.com/open-webui/open-webui/issues/23540), [Commit](https://github.com/open-webui/open-webui/commit/c47dd7b7717c4186e0f0549ca3c8cb4d9bb38135) +- 🧩 **Tool enum value handling.** Tool schema generation now safely handles enum values as strings, preventing failures when OpenAPI parameters include non-string enum entries. [#23597](https://github.com/open-webui/open-webui/issues/23597), [Commit](https://github.com/open-webui/open-webui/commit/4498e6faf2b1bdd1caa0e2c1c15d90a2790cd721) +- 🧷 **Responses model access control.** The OpenAI-compatible Responses endpoint now enforces per-model permissions, preventing non-admin users from accessing models they are not allowed to use. [#23481](https://github.com/open-webui/open-webui/pull/23481) +- 🛡️ **Collection process endpoint permissions.** Collection processing endpoints now enforce collection ownership checks for web and text processing requests. [Commit](https://github.com/open-webui/open-webui/commit/ba83613ff297bc82db660b5273f04672d744902f), [#23634](https://github.com/open-webui/open-webui/pull/23634) +- 📚 **Knowledge query access enforcement.** Knowledge-base collection queries now block unauthorized enumeration and require read access before returning results. [Commit](https://github.com/open-webui/open-webui/commit/860b90fd17d14ba00674621edd294dee150491d2), [#23635](https://github.com/open-webui/open-webui/pull/23635), [#23452](https://github.com/open-webui/open-webui/pull/23452) +- 🔍 **RAG collection query permissions.** Vector search collection queries now enforce access checks before retrieval results are returned. [Commit](https://github.com/open-webui/open-webui/commit/f44b7a01f5b854f47c1594a1ab5f72096f736262), [#23627](https://github.com/open-webui/open-webui/pull/23627) +- 🔗 **Chained base model access checks.** Chained base model execution now enforces per-model access rules to prevent unauthorized model usage. [Commit](https://github.com/open-webui/open-webui/commit/8acce144f99992b75c25f0e5038b16881ce9f066), [Commit](https://github.com/open-webui/open-webui/commit/50363ba66b19613a2fc0cab6a3f7f724a825135e), [#23647](https://github.com/open-webui/open-webui/pull/23647) +- ✍️ **Collaborative document write checks.** Collaborative document updates now require proper write permission before changes are accepted. [Commit](https://github.com/open-webui/open-webui/commit/638c7ab80216452910bdc59a19eb90e6b7244c6c), [Commit](https://github.com/open-webui/open-webui/commit/3271b013a8b30a882364679dcb40ffc9a89f037e), [#23624](https://github.com/open-webui/open-webui/pull/23624) +- 📥 **Model import ownership validation.** Model import now enforces ownership and access grant checks to prevent unauthorized imports. [Commit](https://github.com/open-webui/open-webui/commit/499129625bf96b2c03a6d057a2f91fdf07fd1c49), [#23628](https://github.com/open-webui/open-webui/pull/23628) +- 🚫 **Inactive member channel access.** Deactivated group members can no longer read or write channel content through direct API calls, so channel permissions now match active membership status. [#23623](https://github.com/open-webui/open-webui/pull/23623) +- 🎛️ **Ollama endpoint model permissions.** Restricted models are now protected on Ollama show, generate, embed, and embeddings endpoints, preventing authenticated users from using private models without read access. [#23631](https://github.com/open-webui/open-webui/pull/23631) +- 🧭 **Azure deployment path validation.** Azure model names are now validated and safely encoded before request URL construction, preventing path traversal attempts from reaching unintended Azure endpoints. [#23629](https://github.com/open-webui/open-webui/pull/23629) +- 👥 **Private channel member list access.** Standard channel member lists now require proper read permission, preventing unauthorized users from enumerating members of private channels by direct API calls. [#23625](https://github.com/open-webui/open-webui/pull/23625) +- 🌀 **Tool server schema recursion safety.** Tool server OpenAPI conversion now handles circular request schema references safely, preventing conversion crashes and ensuring one bad tool server spec does not break the full tool server list. [#23588](https://github.com/open-webui/open-webui/pull/23588), [Commit](https://github.com/open-webui/open-webui/commit/d3df8f1f372411314be9121fbf61d107939fa258) +- 🧱 **Safer file path handling.** File upload, transcription cache, and model download paths now use safer path construction helpers to reduce path parsing risks and improve cross-platform path safety. [Commit](https://github.com/open-webui/open-webui/commit/15f9a8f3f13f112c96cb1b16f88859f65de58346) +- 🧾 **Prompt save error feedback.** Saving prompt edits now shows a clear error toast if the save fails, so failed updates are visible instead of silently failing in the editor flow. [Commit](https://github.com/open-webui/open-webui/commit/36a81ad43b7c0d450079f818a7546eaa517e3d95) +- 🧾 **Tool call JSON rendering.** Tool call arguments and structured results now render as plain formatted JSON blocks instead of markdown code fences, preventing formatting quirks and making tool output easier to read consistently. [Commit](https://github.com/open-webui/open-webui/commit/a7d4c53f3adb80768b67e4a410b486b04a581521) +- 👥 **First-user admin race protection.** Concurrent first-time LDAP or OAuth registrations can no longer create multiple admin accounts, so only the true first account is promoted during initial setup. [#23626](https://github.com/open-webui/open-webui/pull/23626) +- 🔒 **SCIM token checks.** SCIM authentication now compares tokens in a safer way, helping prevent timing-based token guessing attacks. [#23577](https://github.com/open-webui/open-webui/pull/23577) +- 🔒 **Safer file access checks.** HTML file previews now treat missing or non-admin owners as inaccessible, preventing accidental access to files that should not be shown. [Commit](https://github.com/open-webui/open-webui/commit/6acaaea59a50ec26da03e6144017a2fd86241ce9) +- 🖼️ **ComfyUI request hangs.** Concurrent image generation and editing requests to ComfyUI now complete reliably instead of getting stuck when the same user starts multiple requests at once. [#23592](https://github.com/open-webui/open-webui/pull/23592), [#23591](https://github.com/open-webui/open-webui/issues/23591) +- 🧭 **Permission-aware built-in tools.** Built-in tools now consistently respect user feature permissions for memories, web search, image generation, code interpreter, notes, channels, and automations, preventing tools from being exposed to users without access. [Commit](https://github.com/open-webui/open-webui/commit/588b81eedaacbfd7394b707ae1600d9fb729b809..674695918e5e3e1811314ce2a082c5bbb42d76b2) +- 🛑 **Interrupted MCP cleanup stability.** Interrupted MCP tool calls no longer leave runaway cleanup behavior that can drive container CPU usage to 100%, keeping instances stable after cancellations or dropped connections. [#23143](https://github.com/open-webui/open-webui/issues/23143) +- 🚪 **OAuth redirect URI reliability.** OAuth login redirects now use provider client metadata more consistently, preventing incorrect HTTP callback URLs behind reverse proxies and improving sign-in reliability for providers such as Feishu. [#23203](https://github.com/open-webui/open-webui/pull/23203), [#23128](https://github.com/open-webui/open-webui/issues/23128) +- 🌐 **OAuth redirect handling.** OAuth provider token exchange now follows redirects automatically, improving sign-in reliability with identity providers that redirect token endpoint requests. [#23409](https://github.com/open-webui/open-webui/issues/23409), [Commit](https://github.com/open-webui/open-webui/commit/498ff8cdc3dd47000cdc60e5adcf36f4adfbe07d) +- ☁️ **OneDrive picker redirect handling.** OneDrive file picker authentication now uses the current app origin as the redirect URI, improving sign-in reliability when launching the picker from deployed environments. [#23450](https://github.com/open-webui/open-webui/issues/23450), [Commit](https://github.com/open-webui/open-webui/commit/21cc8281323d505d7d084cc496bd433063315c86) +- 🍪 **OAuth session cookie persistence.** OIDC sign-in now correctly sets the "oauth_session_id" cookie, so "system_oauth" connections can forward user OAuth tokens to upstream providers as expected. [#23251](https://github.com/open-webui/open-webui/pull/23251), [#23250](https://github.com/open-webui/open-webui/issues/23250) +- 🔑 **OAuth session cookie handling.** OAuth callback processing no longer fails on undefined cookie expiry data, so OAuth session cookies are stored correctly after sign-in. [#23207](https://github.com/open-webui/open-webui/pull/23207), [#23197](https://github.com/open-webui/open-webui/issues/23197) +- 🔏 **Ollama SSL handling.** Ollama model management and file uploads now respect the configured SSL verification setting, so self-signed certificates work when SSL verification is disabled. [#23503](https://github.com/open-webui/open-webui/issues/23503), [Commit](https://github.com/open-webui/open-webui/commit/e51b661af0e71a24f041428f328fcc6e97a15262) +- 🛡️ **OAuth avatar URL validation.** OAuth sign-in now validates profile picture URLs before fetching them, preventing invalid image links from causing login-time errors. [#23356](https://github.com/open-webui/open-webui/pull/23356) +- 🔑 **User invite token expiry.** New user invite logins now respect the configured "JWT_EXPIRES_IN" setting, so signup tokens expire as expected instead of using the default lifetime. [#23576](https://github.com/open-webui/open-webui/pull/23576) +- 🚪 **Channel access checks.** Channel actions now verify the current user when checking access, improving permission enforcement across channel views and message actions. [Commit](https://github.com/open-webui/open-webui/commit/4632f200a9ac98c915aee412b34e86c3d3c58bb1) +- 📣 **Channel message lookups.** Channel message details and pinning now work more reliably when the sender account is missing, avoiding failures in those views. [Commit](https://github.com/open-webui/open-webui/commit/6acaaea59a50ec26da03e6144017a2fd86241ce9) +- 📌 **Pinned webhook message handling.** Viewing pinned webhook messages now works reliably even when webhook profile data is missing, preventing server errors and frontend crashes in channel pinned message dialogs. [#23414](https://github.com/open-webui/open-webui/pull/23414) +- 🛡️ **Note edit permission enforcement.** Note saving now requires write access instead of read access, preventing unauthorized users from modifying notes while preserving expected collaboration permissions. [Commit](https://github.com/open-webui/open-webui/commit/584a9a0920d8c8c72fc89ccbac83c970b5a4bd4a) +- 🗂️ **Archived chats menu visibility.** The 'Archived Chats' option in the user menu is now shown reliably for all users, so non-admin accounts can consistently access archived conversations. [Commit](https://github.com/open-webui/open-webui/commit/07262fa62c2323fc7948389e5b5b8a5d1b72fade) +- 💾 **Error message persistence.** LLM errors that occur during streaming are now saved to the database even if the connection drops, so users can see what went wrong when they reconnect. [#23231](https://github.com/open-webui/open-webui/pull/23231) +- 🚫 **Missing message completion guard.** Chat completion finalization now skips invalid requests without a message identifier, preventing unnecessary error toasts caused by rare frontend concurrency timing. [#23184](https://github.com/open-webui/open-webui/pull/23184) +- 🧠 **Active message completion accuracy.** Switching chats or refreshing during generation no longer marks the currently streaming assistant message as finished too early, so thinking blocks and action buttons appear at the correct time. [#23171](https://github.com/open-webui/open-webui/issues/23171) +- 📞 **Call overlay visibility.** Incoming call events now open the call overlay and controls reliably, preventing cases where the call interface briefly appeared and then disappeared. [Commit](https://github.com/open-webui/open-webui/commit/ee9db91df02120e1e3651e8881734966b710ad52) +- 💬 **Prompt submission handling.** Chat messages now preserve attached files more reliably when prompts are sent, including queued messages and shared prompt actions. [Commit](https://github.com/open-webui/open-webui/commit/6d6dfbf02c893d72d85d4490cb41f1665b1f9f95) +- 🧾 **Prompt variable form saving.** Prompt variable forms now save reliably without runtime errors or an unresponsive save action, so input values and placeholders work correctly when applying prompt templates with variables. [#23225](https://github.com/open-webui/open-webui/issues/23225), [#23480](https://github.com/open-webui/open-webui/issues/23480) +- 🛟 **Task model fallback safety.** Task routing now handles missing default model entries safely, preventing task execution failures when the previously selected model is no longer available. [#23169](https://github.com/open-webui/open-webui/pull/23169) +- 📊 **Usage statistic preservation.** Follow-up generation no longer overwrites existing token usage fields, so stored usage statistics remain accurate for the main response. [#23152](https://github.com/open-webui/open-webui/issues/23152) +- 📝 **Writing block parsing reliability.** ":::writing" blocks now parse more reliably when headers or extra inline text are present, preventing malformed rendering and duplicate output artifacts. [#23174](https://github.com/open-webui/open-webui/issues/23174) +- 🧾 **Code block line break reliability.** Blank lines in submitted code blocks are now preserved more reliably instead of being collapsed. [Commit](https://github.com/open-webui/open-webui/commit/1be9627dd27ffe75957729a4a0d1682a98684f01), [#20302](https://github.com/open-webui/open-webui/issues/20302), [#23451](https://github.com/open-webui/open-webui/pull/23451) +- ✂️ **Citation spacing cleanup.** When citations are disabled for a model, citation markers and their leftover spacing are now removed together so punctuation and copied text remain cleanly formatted. [#23141](https://github.com/open-webui/open-webui/issues/23141) +- 🧰 **Pipe tool access.** Pipe functions now receive built-in and MCP tools in **tools**, so tools like Web Search and code execution are available when enabled. [#23365](https://github.com/open-webui/open-webui/issues/23365) +- 📚 **Batch file processing database handling.** Batch knowledge file processing now consistently uses the active database session, preventing failures caused by missing database context during file ownership checks and update writes. [#23137](https://github.com/open-webui/open-webui/issues/23137) +- ⚙️ **Default model parameter loading.** The "DEFAULT_MODEL_PARAMS" environment variable is now parsed and applied correctly, so default generation settings are honored reliably without being ignored at startup. [#23223](https://github.com/open-webui/open-webui/pull/23223) +- 🔧 **Web search settings save reliability.** Saving web search configuration now works without server errors, so administrators can update "WEB_FETCH_MAX_CONTENT_LENGTH" and related retrieval settings successfully from the admin interface. [Commit](https://github.com/open-webui/open-webui/commit/36d02aa1477aa1b4e7fb59d022f99693ebfa8667), [#23127](https://github.com/open-webui/open-webui/issues/23127) +- 🔍 **Web search result count.** The built-in search_web tool now respects the admin-configured "Search Result Count" setting instead of always returning 5 results when using Native Function Calling mode. [#23488](https://github.com/open-webui/open-webui/pull/23488), [#23485](https://github.com/open-webui/open-webui/issues/23485) +- 🖼️ **Open Terminal file response handling.** Open Terminal tool responses now preserve binary content types in user-side connections, so image and non-text file reads work consistently instead of being forced into plain text. [#23125](https://github.com/open-webui/open-webui/issues/23125) +- 🖥️ **Terminal label casing.** Terminal names in the chat input now display exactly as stored instead of being automatically capitalized, so domain-style server names appear correctly. [#23518](https://github.com/open-webui/open-webui/pull/23518) +- 🖼️ **Gravatar profile photo saving.** Gravatar profile images can now be saved successfully from account settings, with clearer validation and error handling instead of failing with generic object errors. [#23156](https://github.com/open-webui/open-webui/issues/23156) +- 🪟 **Details expansion preference.** Tool call detail groups now honor the 'Always Expand Details' chat setting, so they open expanded by default when that preference is enabled. [#23262](https://github.com/open-webui/open-webui/pull/23262), [#23255](https://github.com/open-webui/open-webui/issues/23255) +- 🖱️ **Rapid sidebar action protection.** Archive and delete actions in the chat sidebar now ignore repeated clicks while a request is in progress, preventing duplicate requests and stacked error toasts. [#23172](https://github.com/open-webui/open-webui/issues/23172) +- 📲 **Mobile model selector positioning.** The mobile model selector dropdown now applies a constrained viewport width and left offset, preventing overflow and making model selection easier on small screens. [#23310](https://github.com/open-webui/open-webui/pull/23310) +- 🔽 **Task list toggle icons.** The task list collapse button now shows the correct arrow direction, making task sections easier to expand and collapse at a glance. [Commit](https://github.com/open-webui/open-webui/commit/f66b67c8b86b6f9d896a23c7bb53907c2e6b15d3), [#23354](https://github.com/open-webui/open-webui/issues/23354) +- ➕ **Attachment menu auto-close.** The chat attachment menu now closes immediately after selecting upload actions like file upload, camera capture, web attach, Google Drive, or OneDrive, preventing the menu from lingering on screen. [Commit](https://github.com/open-webui/open-webui/commit/4764dd5d3765c22384ed38cbc97a8170daa7a75f), [#23320](https://github.com/open-webui/open-webui/issues/23320) +- 🧹 **Per-chat draft clearing.** Sent message drafts are now cleared using the active chat key, so sent text no longer reappears in the input after a refresh. [Commit](https://github.com/open-webui/open-webui/commit/124b7e9154d7f3ca8a16f2b90621209ac8d6b8c1), [#23296](https://github.com/open-webui/open-webui/issues/23296) +- ✉️ **Context-aware input action button.** The input now shows the send action when text or files are present during generation, while keeping stop controls for truly empty input states to avoid action confusion. [Commit](https://github.com/open-webui/open-webui/commit/86472bb4453af7ea4e5ddc8d127b14d8e67733bc), [#23306](https://github.com/open-webui/open-webui/issues/23306) +- 📉 **Pyodide prompt cache stability.** Pyodide code interpreter context is now appended to the system prompt instead of user messages, preserving stable prefix caching across turns and reducing repeated token costs in long native tool-calling chats. [#23269](https://github.com/open-webui/open-webui/issues/23269) +- 🧪 **Temp chat outlet filtering.** Outlet filters now process temporary chats more reliably, preserving assistant output and usage data so local chat responses stay consistent when filter pipelines are enabled. [Commit](https://github.com/open-webui/open-webui/commit/70a6a24f143b221c787bc50b72582ee1e0c2dac0) + +### Changed + +- ⚠️ **Database Migrations**: This release includes database schema changes; we strongly recommend backing up your database and all associated data before upgrading in production environments. If you are running a multi-worker, multi-server, or load-balanced deployment, all instances must be updated simultaneously, rolling updates are not supported and will cause application failures due to schema incompatibility. +- 🧨 **Plugin async migration required.** Custom plugins for Tools, Functions, and Pipelines may require migration to the new async backend signatures after upgrading, so plugin maintainers should update handlers and database call patterns for compatibility and follow the 0.9.0 plugin migration guide. [Migration Guide](https://docs.openwebui.com/features/extensibility/plugin/migration/to-0.9.0) +- 🔄 **Automation terminal source.** Automations now use the terminal configured on the selected model instead of a separate per-automation terminal picker, keeping terminal behavior consistent between chat and scheduled runs. [Commit](https://github.com/open-webui/open-webui/commit/47d413ce7b2a006a8126f4a9055b13e5fcb33a1d) +- 🚧 **OpenAI passthrough now opt-in.** Direct OpenAI catch-all proxy requests are now disabled by default and require enabling "ENABLE_OPENAI_API_PASSTHROUGH", so deployments relying on passthrough must explicitly turn it on after upgrading. [#23640](https://github.com/open-webui/open-webui/pull/23640) +- 🗄️ **SQLite WAL default enabled.** SQLite deployments now default to enabling write-ahead logging, improving concurrent read and write behavior without requiring manual configuration. [Commit](https://github.com/open-webui/open-webui/commit/2f9e326dba3b1087932cb6b8075ed1881bd1c6d6) + ## [0.8.12] - 2026-03-26 ### Added diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 751bbb3153..814746cba8 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1524,6 +1524,8 @@ USER_PERMISSIONS_FEATURES_AUTOMATIONS = ( os.environ.get('USER_PERMISSIONS_FEATURES_AUTOMATIONS', 'False').lower() == 'true' ) +USER_PERMISSIONS_FEATURES_CALENDAR = os.environ.get('USER_PERMISSIONS_FEATURES_CALENDAR', 'True').lower() == 'true' + USER_PERMISSIONS_SETTINGS_INTERFACE = os.environ.get('USER_PERMISSIONS_SETTINGS_INTERFACE', 'True').lower() == 'true' @@ -1594,6 +1596,7 @@ DEFAULT_USER_PERMISSIONS = { 'code_interpreter': USER_PERMISSIONS_FEATURES_CODE_INTERPRETER, 'memories': USER_PERMISSIONS_FEATURES_MEMORIES, 'automations': USER_PERMISSIONS_FEATURES_AUTOMATIONS, + 'calendar': USER_PERMISSIONS_FEATURES_CALENDAR, }, 'settings': { 'interface': USER_PERMISSIONS_SETTINGS_INTERFACE, @@ -1624,6 +1627,18 @@ ENABLE_CHANNELS = PersistentConfig( os.environ.get('ENABLE_CHANNELS', 'False').lower() == 'true', ) +ENABLE_CALENDAR = PersistentConfig( + 'ENABLE_CALENDAR', + 'calendar.enable', + os.environ.get('ENABLE_CALENDAR', 'True').lower() == 'true', +) + +ENABLE_AUTOMATIONS = PersistentConfig( + 'ENABLE_AUTOMATIONS', + 'automations.enable', + os.environ.get('ENABLE_AUTOMATIONS', 'True').lower() == 'true', +) + AUTOMATION_MAX_COUNT = PersistentConfig( 'AUTOMATION_MAX_COUNT', 'automations.max_count', @@ -2977,6 +2992,12 @@ RAG_RERANKING_MODEL_TRUST_REMOTE_CODE = ( os.environ.get('RAG_RERANKING_MODEL_TRUST_REMOTE_CODE', 'True').lower() == 'true' ) +RAG_RERANKING_BATCH_SIZE = PersistentConfig( + 'RAG_RERANKING_BATCH_SIZE', + 'rag.reranking_batch_size', + int(os.environ.get('RAG_RERANKING_BATCH_SIZE', '32')), +) + RAG_EXTERNAL_RERANKER_URL = PersistentConfig( 'RAG_EXTERNAL_RERANKER_URL', 'rag.external_reranker_url', diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index fbabd32361..26a8d376c5 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -375,7 +375,35 @@ else: except Exception: DATABASE_POOL_RECYCLE = 3600 -DATABASE_ENABLE_SQLITE_WAL = os.environ.get('DATABASE_ENABLE_SQLITE_WAL', 'False').lower() == 'true' +DATABASE_ENABLE_SQLITE_WAL = os.environ.get('DATABASE_ENABLE_SQLITE_WAL', 'True').lower() == 'true' + +# SQLite PRAGMA tuning — these defaults are optimised for WAL-mode web-server +# workloads. Each can be overridden via its environment variable. +# Set any value to an empty string to skip that PRAGMA entirely. + +# PRAGMA synchronous: NORMAL (1) is safe with WAL and avoids an fsync per +# transaction. Valid values: OFF (0), NORMAL (1), FULL (2), EXTRA (3). +DATABASE_SQLITE_PRAGMA_SYNCHRONOUS = os.environ.get('DATABASE_SQLITE_PRAGMA_SYNCHRONOUS', 'NORMAL') + +# PRAGMA busy_timeout (ms): how long a connection waits for a write lock +# before raising SQLITE_BUSY. +DATABASE_SQLITE_PRAGMA_BUSY_TIMEOUT = os.environ.get('DATABASE_SQLITE_PRAGMA_BUSY_TIMEOUT', '5000') + +# PRAGMA cache_size: negative value = KiB. -65536 ≈ 64 MB page cache. +DATABASE_SQLITE_PRAGMA_CACHE_SIZE = os.environ.get('DATABASE_SQLITE_PRAGMA_CACHE_SIZE', '-65536') + +# PRAGMA temp_store: MEMORY (2) keeps temp tables and indices in RAM. +# Valid values: DEFAULT (0), FILE (1), MEMORY (2). +DATABASE_SQLITE_PRAGMA_TEMP_STORE = os.environ.get('DATABASE_SQLITE_PRAGMA_TEMP_STORE', 'MEMORY') + +# PRAGMA mmap_size (bytes): memory-mapped I/O size. 268435456 ≈ 256 MB. +# Set to 0 to disable mmap. +DATABASE_SQLITE_PRAGMA_MMAP_SIZE = os.environ.get('DATABASE_SQLITE_PRAGMA_MMAP_SIZE', '268435456') + +# PRAGMA journal_size_limit (bytes): caps the WAL file size after checkpoint. +# Without this the WAL grows unbounded during write bursts and is never +# truncated. 67108864 ≈ 64 MB. Set to -1 for no limit (SQLite default). +DATABASE_SQLITE_PRAGMA_JOURNAL_SIZE_LIMIT = os.environ.get('DATABASE_SQLITE_PRAGMA_JOURNAL_SIZE_LIMIT', '67108864') DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL = os.environ.get('DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL', None) if DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL is not None: @@ -646,6 +674,15 @@ ENABLE_CHAT_RESPONSE_BASE64_IMAGE_URL_CONVERSION = ( os.environ.get('ENABLE_CHAT_RESPONSE_BASE64_IMAGE_URL_CONVERSION', 'False').lower() == 'true' ) +# When enabled, uses a hardcoded extension-to-MIME dictionary as a last-resort +# fallback when both mimetypes.guess_type() and file.meta.content_type fail to +# determine the content type. This can help on minimal container images (e.g. +# wolfi-base) that lack /etc/mime.types AND have legacy files without stored +# content_type metadata. +ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK = ( + os.environ.get('ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK', 'False').lower() == 'true' +) + CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = os.environ.get('CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE', '1') if CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE == '': diff --git a/backend/open_webui/functions.py b/backend/open_webui/functions.py index 37a9011aab..1e032759ea 100644 --- a/backend/open_webui/functions.py +++ b/backend/open_webui/functions.py @@ -34,8 +34,10 @@ from open_webui.utils.plugin import ( load_function_module_by_id, get_function_module_from_cache, ) +from open_webui.utils.access_control import check_model_access -from open_webui.env import GLOBAL_LOG_LEVEL +from open_webui.env import GLOBAL_LOG_LEVEL, BYPASS_MODEL_ACCESS_CONTROL +from open_webui.config import BYPASS_ADMIN_ACCESS_CONTROL from open_webui.utils.misc import ( add_or_update_system_message, @@ -232,11 +234,24 @@ async def generate_function_chat_completion(request, form_data, user, models: di oauth_token = None try: - if request.cookies.get('oauth_session_id', None): + oauth_session_id = request.cookies.get('oauth_session_id', None) + if oauth_session_id: oauth_token = await request.app.state.oauth_manager.get_oauth_token( user.id, - request.cookies.get('oauth_session_id', None), + oauth_session_id, ) + + # Fallback: no cookie (automation, API key, etc.) — use most recent session + if oauth_token is None: + from open_webui.models.oauth_sessions import OAuthSessions + + sessions = await OAuthSessions.get_sessions_by_user_id(user.id) + if sessions: + best = max(sessions, key=lambda s: s.updated_at) + oauth_token = await request.app.state.oauth_manager.get_oauth_token( + user.id, + best.id, + ) except Exception as e: log.error(f'Error getting OAuth token: {e}') @@ -260,6 +275,10 @@ async def generate_function_chat_completion(request, form_data, user, models: di if model_info.base_model_id: form_data['model'] = model_info.base_model_id + if not BYPASS_MODEL_ACCESS_CONTROL: + bypass = isinstance(user, UserModel) and user.role == 'admin' and BYPASS_ADMIN_ACCESS_CONTROL + await check_model_access(user if isinstance(user, UserModel) else UserModel(**user), model_info, bypass) + params = model_info.params.model_dump() if params: diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index 3818543fc7..25aa94591b 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -1,8 +1,10 @@ import os import json import logging +import ssl as _stdlib_ssl from contextlib import asynccontextmanager, contextmanager from typing import Any, Optional +from urllib.parse import parse_qs, urlencode, urlparse, urlunparse from open_webui.internal.wrappers import register_connection from open_webui.env import ( @@ -15,6 +17,12 @@ from open_webui.env import ( DATABASE_POOL_TIMEOUT, DATABASE_ENABLE_SQLITE_WAL, DATABASE_ENABLE_SESSION_SHARING, + DATABASE_SQLITE_PRAGMA_SYNCHRONOUS, + DATABASE_SQLITE_PRAGMA_BUSY_TIMEOUT, + DATABASE_SQLITE_PRAGMA_CACHE_SIZE, + DATABASE_SQLITE_PRAGMA_TEMP_STORE, + DATABASE_SQLITE_PRAGMA_MMAP_SIZE, + DATABASE_SQLITE_PRAGMA_JOURNAL_SIZE_LIMIT, ENABLE_DB_MIGRATIONS, ) from peewee_migrate import Router @@ -29,6 +37,92 @@ from typing_extensions import Self log = logging.getLogger(__name__) +def extract_ssl_mode_from_url(url: str) -> tuple[str, str | None]: + """Strip SSL query-string parameters from a PostgreSQL URL. + + asyncpg and psycopg2 use different query-string keys for SSL + (``ssl`` vs ``sslmode``). This helper removes **both** from the + URL so that each driver can receive the correct parameter through + its own mechanism (query-string re-injection for psycopg2, + ``connect_args`` for asyncpg). + + Returns + ------- + (url_without_ssl, ssl_mode) + *url_without_ssl* is the original URL with ``ssl`` / ``sslmode`` + query parameters removed. *ssl_mode* is the extracted mode + string (e.g. ``'require'``), or ``None`` if neither parameter + was present. + + Non-PostgreSQL URLs are returned unchanged with ``ssl_mode=None``. + """ + if not url or not any(url.startswith(prefix) for prefix in ('postgresql://', 'postgresql+', 'postgres://')): + return url, None + + parsed = urlparse(url) + query_params = parse_qs(parsed.query, keep_blank_values=True) + + # Prefer sslmode (libpq canonical) over the asyncpg-only ssl key. + ssl_mode: str | None = None + for key in ('sslmode', 'ssl'): + values = query_params.pop(key, None) + if values and ssl_mode is None: + ssl_mode = values[0] + + if ssl_mode is None: + # Nothing to strip — return the URL untouched. + return url, None + + # Rebuild the query string without the SSL keys. + remaining_query = urlencode(query_params, doseq=True) + url_without_ssl = urlunparse(parsed._replace(query=remaining_query)) + return url_without_ssl, ssl_mode + + +def build_asyncpg_ssl_args(ssl_mode: str | None) -> dict: + """Convert a libpq-style SSL mode value to asyncpg ``connect_args``. + + Returns a dict suitable for unpacking into + ``create_async_engine(..., connect_args=...)``. + """ + if ssl_mode is None: + return {} + + mode = ssl_mode.lower() + if mode == 'disable': + return {'connect_args': {'ssl': False}} + if mode in ('allow', 'prefer'): + # asyncpg has no direct equivalent — omit to let it try without. + return {} + if mode == 'require': + # SSL required but no certificate verification (matches libpq). + ctx = _stdlib_ssl.create_default_context() + ctx.check_hostname = False + ctx.verify_mode = _stdlib_ssl.CERT_NONE + return {'connect_args': {'ssl': ctx}} + if mode in ('verify-ca', 'verify-full'): + # Full verification — use the system trust store. + ctx = _stdlib_ssl.create_default_context() + if mode == 'verify-ca': + ctx.check_hostname = False + return {'connect_args': {'ssl': ctx}} + + # Unknown value — pass through as-is and let asyncpg decide. + return {'connect_args': {'ssl': ssl_mode}} + + +def reattach_ssl_mode_to_url(url_without_ssl: str, ssl_mode: str | None) -> str: + """Re-append ``sslmode=`` to a cleaned PostgreSQL URL. + + Used for psycopg2 / libpq consumers that expect the canonical + ``sslmode`` query-string key. + """ + if ssl_mode is None: + return url_without_ssl + separator = '&' if '?' in url_without_ssl else '?' + return f'{url_without_ssl}{separator}sslmode={ssl_mode}' + + class JSONField(types.TypeDecorator): impl = types.Text cache_ok = True @@ -54,10 +148,14 @@ class JSONField(types.TypeDecorator): # Workaround to handle the peewee migration # This is required to ensure the peewee migration is handled before the alembic migration def handle_peewee_migration(DATABASE_URL): - # db = None + db = None try: + # Normalize SSL params so psycopg2 always sees `sslmode=` (never `ssl=`). + url_without_ssl, ssl_mode = extract_ssl_mode_from_url(DATABASE_URL) + normalized_url = reattach_ssl_mode_to_url(url_without_ssl, ssl_mode) + # Replace the postgresql:// with postgres:// to handle the peewee migration - db = register_connection(DATABASE_URL.replace('postgresql://', 'postgres://')) + db = register_connection(normalized_url.replace('postgresql://', 'postgres://')) migrate_dir = OPEN_WEBUI_DIR / 'internal' / 'migrations' router = Router(db, logger=log, migrate_dir=migrate_dir) router.run() @@ -73,14 +171,22 @@ def handle_peewee_migration(DATABASE_URL): db.close() # Assert if db connection has been closed - assert db.is_closed(), 'Database connection is still open.' + if db is not None: + assert db.is_closed(), 'Database connection is still open.' if ENABLE_DB_MIGRATIONS: handle_peewee_migration(DATABASE_URL) -SQLALCHEMY_DATABASE_URL = DATABASE_URL +# Normalize SSL params from the URL once; each engine branch re-injects +# the driver-appropriate form. +DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_MODE = extract_ssl_mode_from_url(DATABASE_URL) + +# For psycopg2 (sync engine), re-append sslmode=. +SQLALCHEMY_DATABASE_URL = ( + reattach_ssl_mode_to_url(DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_MODE) if DATABASE_SSL_MODE else DATABASE_URL +) def _make_async_url(url: str) -> str: @@ -155,14 +261,32 @@ if SQLALCHEMY_DATABASE_URL.startswith('sqlite+sqlcipher://'): elif 'sqlite' in SQLALCHEMY_DATABASE_URL: engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={'check_same_thread': False}) - def on_connect(dbapi_connection, connection_record): + def _apply_sqlite_pragmas(dbapi_connection): + """Apply all configured SQLite PRAGMAs to a raw DBAPI connection.""" cursor = dbapi_connection.cursor() if DATABASE_ENABLE_SQLITE_WAL: cursor.execute('PRAGMA journal_mode=WAL') else: cursor.execute('PRAGMA journal_mode=DELETE') + + # Each PRAGMA is skipped when its env var is empty, allowing opt-out. + if DATABASE_SQLITE_PRAGMA_SYNCHRONOUS: + cursor.execute(f'PRAGMA synchronous={DATABASE_SQLITE_PRAGMA_SYNCHRONOUS}') + if DATABASE_SQLITE_PRAGMA_BUSY_TIMEOUT: + cursor.execute(f'PRAGMA busy_timeout={DATABASE_SQLITE_PRAGMA_BUSY_TIMEOUT}') + if DATABASE_SQLITE_PRAGMA_CACHE_SIZE: + cursor.execute(f'PRAGMA cache_size={DATABASE_SQLITE_PRAGMA_CACHE_SIZE}') + if DATABASE_SQLITE_PRAGMA_TEMP_STORE: + cursor.execute(f'PRAGMA temp_store={DATABASE_SQLITE_PRAGMA_TEMP_STORE}') + if DATABASE_SQLITE_PRAGMA_MMAP_SIZE: + cursor.execute(f'PRAGMA mmap_size={DATABASE_SQLITE_PRAGMA_MMAP_SIZE}') + if DATABASE_SQLITE_PRAGMA_JOURNAL_SIZE_LIMIT: + cursor.execute(f'PRAGMA journal_size_limit={DATABASE_SQLITE_PRAGMA_JOURNAL_SIZE_LIMIT}') cursor.close() + def on_connect(dbapi_connection, connection_record): + _apply_sqlite_pragmas(dbapi_connection) + event.listen(engine, 'connect', on_connect) else: if isinstance(DATABASE_POOL_SIZE, int): @@ -205,22 +329,31 @@ get_db = contextmanager(get_session) # ASYNC ENGINE (used for ALL runtime database operations) # ============================================================ -ASYNC_SQLALCHEMY_DATABASE_URL = _make_async_url(SQLALCHEMY_DATABASE_URL) +# Use the SSL-stripped URL for asyncpg — SSL is injected via connect_args. +ASYNC_SQLALCHEMY_DATABASE_URL = _make_async_url( + DATABASE_URL_WITHOUT_SSL if DATABASE_SSL_MODE else SQLALCHEMY_DATABASE_URL +) if 'sqlite' in ASYNC_SQLALCHEMY_DATABASE_URL: + # Generous default — async coroutines + no session sharing = high connection demand. + _sqlite_pool_size = DATABASE_POOL_SIZE if isinstance(DATABASE_POOL_SIZE, int) and DATABASE_POOL_SIZE > 0 else 512 async_engine = create_async_engine( ASYNC_SQLALCHEMY_DATABASE_URL, connect_args={'check_same_thread': False}, + pool_size=_sqlite_pool_size, + pool_timeout=DATABASE_POOL_TIMEOUT, + pool_recycle=DATABASE_POOL_RECYCLE, + pool_pre_ping=True, ) - if DATABASE_ENABLE_SQLITE_WAL: - - @event.listens_for(async_engine.sync_engine, 'connect') - def _set_sqlite_wal(dbapi_connection, connection_record): - cursor = dbapi_connection.cursor() - cursor.execute('PRAGMA journal_mode=WAL') - cursor.close() + @event.listens_for(async_engine.sync_engine, 'connect') + def _set_sqlite_pragmas(dbapi_connection, connection_record): + _apply_sqlite_pragmas(dbapi_connection) else: + # Inject asyncpg-compatible SSL connect_args when the user specified + # sslmode/ssl in DATABASE_URL. + asyncpg_ssl_args = build_asyncpg_ssl_args(DATABASE_SSL_MODE) + if isinstance(DATABASE_POOL_SIZE, int): if DATABASE_POOL_SIZE > 0: async_engine = create_async_engine( @@ -230,17 +363,20 @@ else: pool_timeout=DATABASE_POOL_TIMEOUT, pool_recycle=DATABASE_POOL_RECYCLE, pool_pre_ping=True, + **asyncpg_ssl_args, ) else: async_engine = create_async_engine( ASYNC_SQLALCHEMY_DATABASE_URL, pool_pre_ping=True, poolclass=NullPool, + **asyncpg_ssl_args, ) else: async_engine = create_async_engine( ASYNC_SQLALCHEMY_DATABASE_URL, pool_pre_ping=True, + **asyncpg_ssl_args, ) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 9d02875e7e..00f082f7b4 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -105,6 +105,7 @@ from open_webui.routers import ( scim, terminals, automations, + calendar, ) from open_webui.routers.retrieval import ( @@ -248,6 +249,7 @@ from open_webui.config import ( RAG_EXTERNAL_RERANKER_URL, RAG_EXTERNAL_RERANKER_API_KEY, RAG_EXTERNAL_RERANKER_TIMEOUT, + RAG_RERANKING_BATCH_SIZE, RAG_RERANKING_MODEL_AUTO_UPDATE, RAG_RERANKING_MODEL_TRUST_REMOTE_CODE, RAG_EMBEDDING_ENGINE, @@ -393,9 +395,11 @@ from open_webui.config import ( API_KEYS_ALLOWED_ENDPOINTS, ENABLE_FOLDERS, FOLDER_MAX_FILE_COUNT, + ENABLE_AUTOMATIONS, AUTOMATION_MAX_COUNT, AUTOMATION_MIN_INTERVAL, ENABLE_CHANNELS, + ENABLE_CALENDAR, ENABLE_NOTES, ENABLE_USER_STATUS, ENABLE_COMMUNITY_SHARING, @@ -672,9 +676,9 @@ async def lifespan(app: FastAPI): asyncio.create_task(periodic_usage_pool_cleanup()) asyncio.create_task(periodic_session_pool_cleanup()) - from open_webui.utils.automations import automation_worker_loop + from open_webui.utils.automations import scheduler_worker_loop - asyncio.create_task(automation_worker_loop(app)) + asyncio.create_task(scheduler_worker_loop(app)) if app.state.config.ENABLE_BASE_MODELS_CACHE: try: @@ -899,9 +903,11 @@ app.state.config.BANNERS = WEBUI_BANNERS app.state.config.ENABLE_FOLDERS = ENABLE_FOLDERS app.state.config.FOLDER_MAX_FILE_COUNT = FOLDER_MAX_FILE_COUNT +app.state.config.ENABLE_AUTOMATIONS = ENABLE_AUTOMATIONS app.state.config.AUTOMATION_MAX_COUNT = AUTOMATION_MAX_COUNT app.state.config.AUTOMATION_MIN_INTERVAL = AUTOMATION_MIN_INTERVAL app.state.config.ENABLE_CHANNELS = ENABLE_CHANNELS +app.state.config.ENABLE_CALENDAR = ENABLE_CALENDAR app.state.config.ENABLE_NOTES = ENABLE_NOTES app.state.config.ENABLE_COMMUNITY_SHARING = ENABLE_COMMUNITY_SHARING app.state.config.ENABLE_MESSAGE_RATING = ENABLE_MESSAGE_RATING @@ -1048,6 +1054,7 @@ app.state.config.RAG_RERANKING_MODEL = RAG_RERANKING_MODEL app.state.config.RAG_EXTERNAL_RERANKER_URL = RAG_EXTERNAL_RERANKER_URL app.state.config.RAG_EXTERNAL_RERANKER_API_KEY = RAG_EXTERNAL_RERANKER_API_KEY app.state.config.RAG_EXTERNAL_RERANKER_TIMEOUT = RAG_EXTERNAL_RERANKER_TIMEOUT +app.state.config.RAG_RERANKING_BATCH_SIZE = RAG_RERANKING_BATCH_SIZE app.state.config.RAG_TEMPLATE = RAG_TEMPLATE @@ -1197,6 +1204,7 @@ app.state.RERANKING_FUNCTION = get_reranking_function( app.state.config.RAG_RERANKING_ENGINE, app.state.config.RAG_RERANKING_MODEL, reranking_function=app.state.rf, + reranking_batch_size=app.state.config.RAG_RERANKING_BATCH_SIZE, ) ######################################## @@ -1434,6 +1442,7 @@ if ENABLE_ADMIN_ANALYTICS: app.include_router(utils.router, prefix='/api/v1/utils', tags=['utils']) app.include_router(terminals.router, prefix='/api/v1/terminals', tags=['terminals']) app.include_router(automations.router, prefix='/api/v1/automations', tags=['automations']) +app.include_router(calendar.router, prefix='/api/v1/calendars', tags=['calendars']) # SCIM 2.0 API for identity management if ENABLE_SCIM: @@ -1824,6 +1833,8 @@ async def chat_completion( request.state.metadata = metadata form_data['metadata'] = metadata + except HTTPException: + raise except Exception as e: log.debug(f'Error processing chat metadata: {e}') raise HTTPException( @@ -1870,7 +1881,8 @@ async def chat_completion( finally: raise # re-raise to ensure proper task cancellation handling except Exception as e: - log.error('Error processing chat payload: %s', e) + error_detail = e.detail if isinstance(e, HTTPException) else str(e) + log.error('Error processing chat payload: %s', error_detail) if metadata.get('chat_id') and metadata.get('message_id'): # Update the chat message with the error try: @@ -1880,7 +1892,7 @@ async def chat_completion( metadata['message_id'], { 'parentId': metadata.get('user_message_id', None), - 'error': {'content': str(e)}, + 'error': {'content': error_detail}, }, ) @@ -1889,7 +1901,7 @@ async def chat_completion( await event_emitter( { 'type': 'chat:message:error', - 'data': {'error': {'content': str(e)}}, + 'data': {'error': {'content': error_detail}}, } ) await event_emitter( @@ -2215,6 +2227,8 @@ async def get_app_config(request: Request): 'enable_folders': app.state.config.ENABLE_FOLDERS, 'folder_max_file_count': app.state.config.FOLDER_MAX_FILE_COUNT, 'enable_channels': app.state.config.ENABLE_CHANNELS, + 'enable_calendar': app.state.config.ENABLE_CALENDAR, + 'enable_automations': app.state.config.ENABLE_AUTOMATIONS, 'enable_notes': app.state.config.ENABLE_NOTES, 'enable_web_search': app.state.config.ENABLE_WEB_SEARCH, 'enable_code_execution': app.state.config.ENABLE_CODE_EXECUTION, diff --git a/backend/open_webui/migrations/env.py b/backend/open_webui/migrations/env.py index 9ee6c2dceb..f5e57920ea 100644 --- a/backend/open_webui/migrations/env.py +++ b/backend/open_webui/migrations/env.py @@ -3,7 +3,9 @@ from logging.config import fileConfig from alembic import context from open_webui.models.auths import Auth +from open_webui.models.calendar import Calendar, CalendarEvent, CalendarEventAttendee # noqa: F401 from open_webui.env import DATABASE_URL, DATABASE_PASSWORD, LOG_FORMAT +from open_webui.internal.db import extract_ssl_mode_from_url, reattach_ssl_mode_to_url from sqlalchemy import engine_from_config, pool, create_engine # this is the Alembic Config object, which provides @@ -35,6 +37,10 @@ target_metadata = Auth.metadata DB_URL = DATABASE_URL +# Normalize SSL query params for psycopg2 (Alembic uses psycopg2, not asyncpg). +url_without_ssl, ssl_mode = extract_ssl_mode_from_url(DB_URL) +DB_URL = reattach_ssl_mode_to_url(url_without_ssl, ssl_mode) if ssl_mode else DB_URL + if DB_URL: config.set_main_option('sqlalchemy.url', DB_URL.replace('%', '%%')) diff --git a/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py b/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py new file mode 100644 index 0000000000..e556440f56 --- /dev/null +++ b/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py @@ -0,0 +1,83 @@ +"""add calendar tables + +Revision ID: 56359461a091 +Revises: c1d2e3f4a5b6 +Create Date: 2026-04-19 16:20:58.162045 + +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '56359461a091' +down_revision: Union[str, None] = 'c1d2e3f4a5b6' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.create_table( + 'calendar', + sa.Column('id', sa.Text(), nullable=False), + sa.Column('user_id', sa.Text(), nullable=False), + sa.Column('name', sa.Text(), nullable=False), + sa.Column('color', sa.Text(), nullable=True), + sa.Column('is_default', sa.Boolean(), nullable=False), + sa.Column('data', sa.JSON(), nullable=True), + sa.Column('meta', sa.JSON(), nullable=True), + sa.Column('created_at', sa.BigInteger(), nullable=False), + sa.Column('updated_at', sa.BigInteger(), nullable=False), + sa.PrimaryKeyConstraint('id'), + ) + op.create_index('ix_calendar_user', 'calendar', ['user_id'], unique=False) + + op.create_table( + 'calendar_event', + sa.Column('id', sa.Text(), nullable=False), + sa.Column('calendar_id', sa.Text(), nullable=False), + sa.Column('user_id', sa.Text(), nullable=False), + sa.Column('title', sa.Text(), nullable=False), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('start_at', sa.BigInteger(), nullable=False), + sa.Column('end_at', sa.BigInteger(), nullable=True), + sa.Column('all_day', sa.Boolean(), nullable=False), + sa.Column('rrule', sa.Text(), nullable=True), + sa.Column('color', sa.Text(), nullable=True), + sa.Column('location', sa.Text(), nullable=True), + sa.Column('data', sa.JSON(), nullable=True), + sa.Column('meta', sa.JSON(), nullable=True), + sa.Column('is_cancelled', sa.Boolean(), nullable=False), + sa.Column('created_at', sa.BigInteger(), nullable=False), + sa.Column('updated_at', sa.BigInteger(), nullable=False), + sa.PrimaryKeyConstraint('id'), + ) + op.create_index('ix_calendar_event_calendar', 'calendar_event', ['calendar_id', 'start_at'], unique=False) + op.create_index('ix_calendar_event_user_date', 'calendar_event', ['user_id', 'start_at'], unique=False) + + op.create_table( + 'calendar_event_attendee', + sa.Column('id', sa.Text(), nullable=False), + sa.Column('event_id', sa.Text(), nullable=False), + sa.Column('user_id', sa.Text(), nullable=False), + sa.Column('status', sa.Text(), nullable=False), + sa.Column('meta', sa.JSON(), nullable=True), + sa.Column('created_at', sa.BigInteger(), nullable=False), + sa.Column('updated_at', sa.BigInteger(), nullable=False), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('event_id', 'user_id', name='uq_event_attendee'), + ) + op.create_index('ix_calendar_event_attendee_user', 'calendar_event_attendee', ['user_id', 'status'], unique=False) + + +def downgrade() -> None: + op.drop_index('ix_calendar_event_attendee_user', table_name='calendar_event_attendee') + op.drop_table('calendar_event_attendee') + op.drop_index('ix_calendar_event_user_date', table_name='calendar_event') + op.drop_index('ix_calendar_event_calendar', table_name='calendar_event') + op.drop_table('calendar_event') + op.drop_index('ix_calendar_user', table_name='calendar') + op.drop_table('calendar') diff --git a/backend/open_webui/migrations/versions/c1d2e3f4a5b6_add_shared_chat_table.py b/backend/open_webui/migrations/versions/c1d2e3f4a5b6_add_shared_chat_table.py new file mode 100644 index 0000000000..2451f50ae2 --- /dev/null +++ b/backend/open_webui/migrations/versions/c1d2e3f4a5b6_add_shared_chat_table.py @@ -0,0 +1,164 @@ +"""Add shared_chat table and migrate existing shares + +Revision ID: c1d2e3f4a5b6 +Revises: e1f2a3b4c5d6 +Create Date: 2026-04-16 23:00:00.000000 + +""" + +import time +import uuid + +from alembic import op +import sqlalchemy as sa + +revision = 'c1d2e3f4a5b6' +down_revision = 'e1f2a3b4c5d6' +branch_labels = None +depends_on = None + +# Lightweight table references for data migration (no ORM models needed) +chat_t = sa.table( + 'chat', + sa.column('id', sa.Text), + sa.column('user_id', sa.Text), + sa.column('title', sa.Text), + sa.column('chat', sa.JSON), + sa.column('share_id', sa.Text), + sa.column('created_at', sa.BigInteger), + sa.column('updated_at', sa.BigInteger), + sa.column('archived', sa.Boolean), + sa.column('meta', sa.JSON), +) + +shared_chat_t = sa.table( + 'shared_chat', + sa.column('id', sa.Text), + sa.column('chat_id', sa.Text), + sa.column('user_id', sa.Text), + sa.column('title', sa.Text), + sa.column('chat', sa.JSON), + sa.column('created_at', sa.BigInteger), + sa.column('updated_at', sa.BigInteger), +) + +chat_message_t = sa.table( + 'chat_message', + sa.column('chat_id', sa.Text), +) + +access_grant_t = sa.table( + 'access_grant', + sa.column('id', sa.Text), + sa.column('resource_type', sa.Text), + sa.column('resource_id', sa.Text), + sa.column('principal_type', sa.Text), + sa.column('principal_id', sa.Text), + sa.column('permission', sa.Text), + sa.column('created_at', sa.BigInteger), +) + + +def upgrade(): + conn = op.get_bind() + + # 1. Create shared_chat table + op.create_table( + 'shared_chat', + sa.Column('id', sa.Text(), primary_key=True), + sa.Column('chat_id', sa.Text(), sa.ForeignKey('chat.id', ondelete='CASCADE'), nullable=False), + sa.Column('user_id', sa.Text(), nullable=False), + sa.Column('title', sa.Text(), nullable=True), + sa.Column('chat', sa.JSON(), nullable=True), + sa.Column('created_at', sa.BigInteger(), nullable=True), + sa.Column('updated_at', sa.BigInteger(), nullable=True), + ) + + # 2. Migrate existing shared-* rows + shared_rows = conn.execute( + sa.select( + chat_t.c.id, + chat_t.c.user_id, + chat_t.c.title, + chat_t.c.chat, + chat_t.c.created_at, + chat_t.c.updated_at, + ).where(chat_t.c.user_id.like('shared-%')) + ).fetchall() + + for row in shared_rows: + share_token = row.id + original_chat_id = row.user_id.replace('shared-', '', 1) + + # Verify original chat still exists + original = conn.execute(sa.select(chat_t.c.user_id).where(chat_t.c.id == original_chat_id)).fetchone() + + if not original: + continue + + # Insert snapshot into shared_chat + conn.execute( + shared_chat_t.insert().values( + id=share_token, + chat_id=original_chat_id, + user_id=original.user_id, + title=row.title, + chat=row.chat, + created_at=row.created_at, + updated_at=row.updated_at, + ) + ) + + # Create user:*:read grant for backward compat + conn.execute( + access_grant_t.insert().values( + id=str(uuid.uuid4()), + resource_type='shared_chat', + resource_id=original_chat_id, + principal_type='user', + principal_id='*', + permission='read', + created_at=row.created_at or int(time.time()), + ) + ) + + # 3. Clean up old phantom rows + conn.execute( + chat_message_t.delete().where( + chat_message_t.c.chat_id.in_(sa.select(chat_t.c.id).where(chat_t.c.user_id.like('shared-%'))) + ) + ) + conn.execute(chat_t.delete().where(chat_t.c.user_id.like('shared-%'))) + + +def downgrade(): + conn = op.get_bind() + + shared_rows = conn.execute( + sa.select( + shared_chat_t.c.id, + shared_chat_t.c.chat_id, + shared_chat_t.c.user_id, + shared_chat_t.c.title, + shared_chat_t.c.chat, + shared_chat_t.c.created_at, + shared_chat_t.c.updated_at, + ) + ).fetchall() + + for row in shared_rows: + conn.execute( + chat_t.insert().values( + id=row.id, + user_id=f'shared-{row.chat_id}', + title=row.title, + chat=row.chat, + created_at=row.created_at, + updated_at=row.updated_at, + archived=False, + meta={}, + ) + ) + + conn.execute(access_grant_t.delete().where(access_grant_t.c.resource_type == 'shared_chat')) + op.drop_table('shared_chat') diff --git a/backend/open_webui/models/automations.py b/backend/open_webui/models/automations.py index c891c3204e..05f449ad13 100644 --- a/backend/open_webui/models/automations.py +++ b/backend/open_webui/models/automations.py @@ -153,6 +153,14 @@ class AutomationTable: row = await db.get(Automation, id) return AutomationModel.model_validate(row) if row else None + async def get_active_by_user(self, user_id: str, db: Optional[AsyncSession] = None) -> list[AutomationModel]: + """Get active automations for a user (for calendar RRULE expansion).""" + async with get_async_db_context(db) as db: + result = await db.execute( + select(Automation).filter_by(user_id=user_id, is_active=True).order_by(Automation.created_at.desc()) + ) + return [AutomationModel.model_validate(r) for r in result.scalars().all()] + async def search_automations( self, user_id: str, @@ -273,9 +281,19 @@ class AutomationTable: from open_webui.utils.automations import next_run_ns + # Batch-fetch user timezones so rescheduling respects each + # user's local timezone instead of falling back to server time. + user_ids = list({row.user_id for row in rows}) + timezone_by_user_id: dict[str, Optional[str]] = {} + if user_ids: + from open_webui.models.users import User + + tz_result = await db.execute(select(User.id, User.timezone).where(User.id.in_(user_ids))) + timezone_by_user_id = {uid: tz for uid, tz in tz_result.all()} + for row in rows: row.last_run_at = now_ns - row.next_run_at = next_run_ns(row.data.get('rrule', '')) + row.next_run_at = next_run_ns(row.data.get('rrule', ''), tz=timezone_by_user_id.get(row.user_id)) await db.commit() @@ -372,6 +390,32 @@ class AutomationRunTable: await db.commit() return result.rowcount + async def get_runs_by_user_range( + self, + user_id: str, + start_ns: int, + end_ns: int, + limit: int = 500, + db: Optional[AsyncSession] = None, + ) -> list[tuple['AutomationRunModel', 'AutomationModel']]: + """Get runs within a date range for a user, joined with parent automation.""" + async with get_async_db_context(db) as db: + result = await db.execute( + select(AutomationRun, Automation) + .join(Automation, Automation.id == AutomationRun.automation_id) + .filter( + Automation.user_id == user_id, + AutomationRun.created_at >= start_ns, + AutomationRun.created_at < end_ns, + ) + .order_by(AutomationRun.created_at.desc()) + .limit(limit) + ) + return [ + (AutomationRunModel.model_validate(run), AutomationModel.model_validate(auto)) + for run, auto in result.all() + ] + Automations = AutomationTable() AutomationRuns = AutomationRunTable() diff --git a/backend/open_webui/models/calendar.py b/backend/open_webui/models/calendar.py new file mode 100644 index 0000000000..47f0a6f722 --- /dev/null +++ b/backend/open_webui/models/calendar.py @@ -0,0 +1,822 @@ +import time +import logging +from typing import Optional +from uuid import uuid4 + +from pydantic import BaseModel, ConfigDict, Field +from sqlalchemy import ( + Column, + Text, + JSON, + Boolean, + BigInteger, + Index, + UniqueConstraint, + select, + or_, + exists, + func, + delete, + update, +) +from sqlalchemy.ext.asyncio import AsyncSession + +from open_webui.internal.db import Base, get_async_db_context +from open_webui.models.access_grants import AccessGrantModel, AccessGrants +from open_webui.models.groups import Groups +from open_webui.models.users import User, UserModel, UserResponse + +log = logging.getLogger(__name__) + + +#################### +# Calendar DB Schema +#################### + + +class Calendar(Base): + __tablename__ = 'calendar' + + id = Column(Text, primary_key=True) + user_id = Column(Text, nullable=False) + name = Column(Text, nullable=False) + color = Column(Text, nullable=True) + is_default = Column(Boolean, nullable=False, default=False) + data = Column(JSON, nullable=True) + meta = Column(JSON, nullable=True) + + created_at = Column(BigInteger, nullable=False) + updated_at = Column(BigInteger, nullable=False) + + __table_args__ = (Index('ix_calendar_user', 'user_id'),) + + +class CalendarEvent(Base): + __tablename__ = 'calendar_event' + + id = Column(Text, primary_key=True) + calendar_id = Column(Text, nullable=False) + user_id = Column(Text, nullable=False) + title = Column(Text, nullable=False) + description = Column(Text, nullable=True) + start_at = Column(BigInteger, nullable=False) + end_at = Column(BigInteger, nullable=True) + all_day = Column(Boolean, nullable=False, default=False) + rrule = Column(Text, nullable=True) + color = Column(Text, nullable=True) + location = Column(Text, nullable=True) + data = Column(JSON, nullable=True) + meta = Column(JSON, nullable=True) + is_cancelled = Column(Boolean, nullable=False, default=False) + + created_at = Column(BigInteger, nullable=False) + updated_at = Column(BigInteger, nullable=False) + + __table_args__ = ( + Index('ix_calendar_event_calendar', 'calendar_id', 'start_at'), + Index('ix_calendar_event_user_date', 'user_id', 'start_at'), + ) + + +class CalendarEventAttendee(Base): + __tablename__ = 'calendar_event_attendee' + + id = Column(Text, primary_key=True) + event_id = Column(Text, nullable=False) + user_id = Column(Text, nullable=False) + status = Column(Text, nullable=False, default='pending') + meta = Column(JSON, nullable=True) + + created_at = Column(BigInteger, nullable=False) + updated_at = Column(BigInteger, nullable=False) + + __table_args__ = ( + UniqueConstraint('event_id', 'user_id', name='uq_event_attendee'), + Index('ix_calendar_event_attendee_user', 'user_id', 'status'), + ) + + +#################### +# Pydantic Models +#################### + + +class CalendarModel(BaseModel): + model_config = ConfigDict(from_attributes=True) + + id: str + user_id: str + name: str + color: Optional[str] = None + is_default: bool = False + is_system: bool = False + + data: Optional[dict] = None + meta: Optional[dict] = None + + access_grants: list[AccessGrantModel] = Field(default_factory=list) + + created_at: int + updated_at: int + + +class CalendarEventModel(BaseModel): + model_config = ConfigDict(from_attributes=True, extra='allow') + + id: str + calendar_id: str + user_id: str + title: str + description: Optional[str] = None + start_at: int + end_at: Optional[int] = None + all_day: bool = False + rrule: Optional[str] = None + color: Optional[str] = None + location: Optional[str] = None + data: Optional[dict] = None + meta: Optional[dict] = None + is_cancelled: bool = False + + attendees: list['CalendarEventAttendeeModel'] = Field(default_factory=list) + + created_at: int + updated_at: int + + +class CalendarEventAttendeeModel(BaseModel): + model_config = ConfigDict(from_attributes=True) + + id: str + event_id: str + user_id: str + status: str = 'pending' + meta: Optional[dict] = None + + created_at: int + updated_at: int + + +#################### +# Forms +#################### + + +class CalendarForm(BaseModel): + name: str + color: Optional[str] = None + data: Optional[dict] = None + meta: Optional[dict] = None + access_grants: Optional[list[dict]] = None + + +class CalendarUpdateForm(BaseModel): + name: Optional[str] = None + color: Optional[str] = None + data: Optional[dict] = None + meta: Optional[dict] = None + access_grants: Optional[list[dict]] = None + + +class CalendarEventForm(BaseModel): + calendar_id: str + title: str + description: Optional[str] = None + start_at: int + end_at: Optional[int] = None + all_day: bool = False + rrule: Optional[str] = None + color: Optional[str] = None + location: Optional[str] = None + data: Optional[dict] = None + meta: Optional[dict] = None + attendees: Optional[list[dict]] = None + + +class CalendarEventUpdateForm(BaseModel): + calendar_id: Optional[str] = None + title: Optional[str] = None + description: Optional[str] = None + start_at: Optional[int] = None + end_at: Optional[int] = None + all_day: Optional[bool] = None + rrule: Optional[str] = None + color: Optional[str] = None + location: Optional[str] = None + data: Optional[dict] = None + meta: Optional[dict] = None + is_cancelled: Optional[bool] = None + attendees: Optional[list[dict]] = None + + +class RSVPForm(BaseModel): + status: str # 'accepted' | 'declined' | 'tentative' | 'pending' + + +#################### +# Response Models +#################### + + +class CalendarEventUserResponse(CalendarEventModel): + user: Optional[UserResponse] = None + + +class CalendarEventListResponse(BaseModel): + items: list[CalendarEventUserResponse] + total: int + + +#################### +# Table Operations +#################### + + +class CalendarTable: + async def _get_access_grants(self, calendar_id: str, db: Optional[AsyncSession] = None) -> list[AccessGrantModel]: + return await AccessGrants.get_grants_by_resource('calendar', calendar_id, db=db) + + async def _to_calendar_model( + self, + cal: Calendar, + access_grants: Optional[list[AccessGrantModel]] = None, + db: Optional[AsyncSession] = None, + ) -> CalendarModel: + cal_data = CalendarModel.model_validate(cal).model_dump(exclude={'access_grants'}) + cal_data['access_grants'] = ( + access_grants if access_grants is not None else await self._get_access_grants(cal_data['id'], db=db) + ) + return CalendarModel.model_validate(cal_data) + + async def get_or_create_defaults(self, user_id: str, db: Optional[AsyncSession] = None) -> list[CalendarModel]: + """Return user's calendars, creating 'Personal' default if none exist.""" + async with get_async_db_context(db) as db: + result = await db.execute( + select(Calendar).filter(Calendar.user_id == user_id).order_by(Calendar.created_at.asc()) + ) + calendars = result.scalars().all() + + if calendars: + return [CalendarModel.model_validate(c) for c in calendars] + + now = int(time.time_ns()) + cal = Calendar( + id=str(uuid4()), + user_id=user_id, + name='Personal', + color='#3b82f6', + is_default=True, + created_at=now, + updated_at=now, + ) + db.add(cal) + await db.commit() + return [CalendarModel.model_validate(cal)] + + async def get_calendars_by_user(self, user_id: str, db: Optional[AsyncSession] = None) -> list[CalendarModel]: + """Owned + shared calendars.""" + async with get_async_db_context(db) as db: + user_groups = await Groups.get_groups_by_member_id(user_id, db=db) + user_group_ids = [g.id for g in user_groups] + + stmt = select(Calendar) + stmt = AccessGrants.has_permission_filter( + db=db, + query=stmt, + DocumentModel=Calendar, + filter={'user_id': user_id, 'group_ids': user_group_ids}, + resource_type='calendar', + permission='read', + ) + stmt = stmt.order_by(Calendar.created_at.asc()) + + result = await db.execute(stmt) + calendars = result.scalars().all() + + if not calendars: + return await self.get_or_create_defaults(user_id, db=db) + + cal_ids = [c.id for c in calendars] + grants_map = await AccessGrants.get_grants_by_resources('calendar', cal_ids, db=db) + + return [await self._to_calendar_model(c, access_grants=grants_map.get(c.id, []), db=db) for c in calendars] + + async def get_calendar_by_id(self, id: str, db: Optional[AsyncSession] = None) -> Optional[CalendarModel]: + async with get_async_db_context(db) as db: + result = await db.execute(select(Calendar).filter(Calendar.id == id)) + cal = result.scalars().first() + return await self._to_calendar_model(cal, db=db) if cal else None + + async def insert_new_calendar( + self, user_id: str, form_data: CalendarForm, db: Optional[AsyncSession] = None + ) -> Optional[CalendarModel]: + async with get_async_db_context(db) as db: + now = int(time.time_ns()) + cal = Calendar( + id=str(uuid4()), + user_id=user_id, + name=form_data.name, + color=form_data.color, + is_default=False, + data=form_data.data, + meta=form_data.meta, + created_at=now, + updated_at=now, + ) + db.add(cal) + await db.commit() + if form_data.access_grants is not None: + await AccessGrants.set_access_grants('calendar', cal.id, form_data.access_grants, db=db) + return await self._to_calendar_model(cal, db=db) + + async def update_calendar_by_id( + self, id: str, form_data: CalendarUpdateForm, db: Optional[AsyncSession] = None + ) -> Optional[CalendarModel]: + async with get_async_db_context(db) as db: + result = await db.execute(select(Calendar).filter(Calendar.id == id)) + cal = result.scalars().first() + if not cal: + return None + + update_data = form_data.model_dump(exclude_unset=True) + if 'name' in update_data: + cal.name = update_data['name'] + if 'color' in update_data: + cal.color = update_data['color'] + if 'data' in update_data: + cal.data = {**(cal.data or {}), **update_data['data']} + if 'meta' in update_data: + cal.meta = {**(cal.meta or {}), **update_data['meta']} + if 'access_grants' in update_data: + await AccessGrants.set_access_grants('calendar', id, update_data['access_grants'], db=db) + + cal.updated_at = int(time.time_ns()) + await db.commit() + return await self._to_calendar_model(cal, db=db) + + async def set_default_calendar( + self, user_id: str, calendar_id: str, db: Optional[AsyncSession] = None + ) -> Optional[CalendarModel]: + """Set a calendar as the user's default, clearing all others.""" + async with get_async_db_context(db) as db: + # Clear all defaults for this user + await db.execute( + update(Calendar) + .where(Calendar.user_id == user_id, Calendar.is_default == True) + .values(is_default=False) + ) + # Set the new default + result = await db.execute(select(Calendar).filter(Calendar.id == calendar_id, Calendar.user_id == user_id)) + cal = result.scalars().first() + if not cal: + return None + cal.is_default = True + cal.updated_at = int(time.time_ns()) + await db.commit() + return await self._to_calendar_model(cal, db=db) + + async def delete_calendar_by_id(self, id: str, db: Optional[AsyncSession] = None) -> bool: + """Delete a non-default calendar. Cascades to events, attendees, and grants.""" + try: + async with get_async_db_context(db) as db: + result = await db.execute(select(Calendar).filter(Calendar.id == id)) + cal = result.scalars().first() + if not cal or cal.is_default: + return False + + # Delete attendees for all events in this calendar + event_ids_result = await db.execute(select(CalendarEvent.id).filter(CalendarEvent.calendar_id == id)) + event_ids = [r[0] for r in event_ids_result.all()] + if event_ids: + await db.execute( + delete(CalendarEventAttendee).filter(CalendarEventAttendee.event_id.in_(event_ids)) + ) + + # Delete events + await db.execute(delete(CalendarEvent).filter(CalendarEvent.calendar_id == id)) + + # Delete access grants + await AccessGrants.revoke_all_access('calendar', id, db=db) + + # Delete calendar + await db.execute(delete(Calendar).filter(Calendar.id == id)) + await db.commit() + return True + except Exception: + return False + + +class CalendarEventTable: + async def _get_attendees( + self, event_id: str, db: Optional[AsyncSession] = None + ) -> list[CalendarEventAttendeeModel]: + async with get_async_db_context(db) as db: + result = await db.execute(select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id)) + rows = result.scalars().all() + return [CalendarEventAttendeeModel.model_validate(r) for r in rows] + + async def _to_event_model( + self, + event: CalendarEvent, + attendees: Optional[list[CalendarEventAttendeeModel]] = None, + db: Optional[AsyncSession] = None, + ) -> CalendarEventModel: + event_data = CalendarEventModel.model_validate(event).model_dump(exclude={'attendees'}) + event_data['attendees'] = ( + attendees if attendees is not None else await self._get_attendees(event_data['id'], db=db) + ) + return CalendarEventModel.model_validate(event_data) + + async def insert_new_event( + self, user_id: str, form_data: CalendarEventForm, db: Optional[AsyncSession] = None + ) -> Optional[CalendarEventModel]: + async with get_async_db_context(db) as db: + now = int(time.time_ns()) + event = CalendarEvent( + id=str(uuid4()), + calendar_id=form_data.calendar_id, + user_id=user_id, + title=form_data.title, + description=form_data.description, + start_at=form_data.start_at, + end_at=form_data.end_at, + all_day=form_data.all_day, + rrule=form_data.rrule, + color=form_data.color, + location=form_data.location, + data=form_data.data, + meta=form_data.meta, + is_cancelled=False, + created_at=now, + updated_at=now, + ) + db.add(event) + await db.commit() + + # Add attendees + if form_data.attendees: + await CalendarEventAttendees.set_attendees(event.id, form_data.attendees, db=db) + + return await self._to_event_model(event, db=db) + + async def get_event_by_id(self, id: str, db: Optional[AsyncSession] = None) -> Optional[CalendarEventModel]: + async with get_async_db_context(db) as db: + result = await db.execute(select(CalendarEvent).filter(CalendarEvent.id == id)) + event = result.scalars().first() + return await self._to_event_model(event, db=db) if event else None + + async def get_events_by_range( + self, + user_id: str, + start: int, + end: int, + calendar_ids: Optional[list[str]] = None, + db: Optional[AsyncSession] = None, + ) -> list[CalendarEventUserResponse]: + """Fetch events visible to user within a date range. + + Visible events = events in owned/shared calendars + events user attends. + Recurring events are fetched if they have any rrule (expansion in Python). + """ + async with get_async_db_context(db) as db: + user_groups = await Groups.get_groups_by_member_id(user_id, db=db) + user_group_ids = [g.id for g in user_groups] + + # Get calendar IDs accessible to user + cal_stmt = select(Calendar.id) + cal_stmt = AccessGrants.has_permission_filter( + db=db, + query=cal_stmt, + DocumentModel=Calendar, + filter={'user_id': user_id, 'group_ids': user_group_ids}, + resource_type='calendar', + permission='read', + ) + cal_result = await db.execute(cal_stmt) + accessible_cal_ids = [r[0] for r in cal_result.all()] + + if calendar_ids: + # Filter to requested calendars only + accessible_cal_ids = [c for c in accessible_cal_ids if c in calendar_ids] + + # Also get event IDs where user is an attendee + attendee_event_ids_result = await db.execute( + select(CalendarEventAttendee.event_id).filter(CalendarEventAttendee.user_id == user_id) + ) + attendee_event_ids = [r[0] for r in attendee_event_ids_result.all()] + + # Build conditions for accessible events + conditions = [] + if accessible_cal_ids: + conditions.append(CalendarEvent.calendar_id.in_(accessible_cal_ids)) + if attendee_event_ids: + conditions.append(CalendarEvent.id.in_(attendee_event_ids)) + + if not conditions: + return [] + + # Build event query + stmt = ( + select(CalendarEvent, User) + .outerjoin(User, User.id == CalendarEvent.user_id) + .filter( + CalendarEvent.is_cancelled == False, + or_(*conditions), + or_( + # Non-recurring: overlaps the range + ( + CalendarEvent.rrule.is_(None) + & (CalendarEvent.start_at < end) + & or_( + CalendarEvent.end_at.is_(None) & (CalendarEvent.start_at >= start), + CalendarEvent.end_at.isnot(None) & (CalendarEvent.end_at > start), + ) + ), + # Recurring: fetch all (expansion in Python) + CalendarEvent.rrule.isnot(None), + ), + ) + .order_by(CalendarEvent.start_at.asc()) + ) + + result = await db.execute(stmt) + items = result.all() + + if not items: + return [] + + # Batch-load attendees for all events in one query (avoid N+1) + event_ids = [event.id for event, _user in items] + att_result = await db.execute( + select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id.in_(event_ids)) + ) + att_rows = att_result.scalars().all() + att_map: dict[str, list[CalendarEventAttendeeModel]] = {} + for a in att_rows: + att_map.setdefault(a.event_id, []).append(CalendarEventAttendeeModel.model_validate(a)) + + events = [] + for event, user in items: + event_data = CalendarEventModel.model_validate(event).model_dump(exclude={'attendees'}) + event_data['attendees'] = att_map.get(event.id, []) + events.append( + CalendarEventUserResponse( + **event_data, + user=(UserResponse(**UserModel.model_validate(user).model_dump()) if user else None), + ) + ) + + return events + + async def search_events( + self, + user_id: str, + query: Optional[str] = None, + skip: int = 0, + limit: int = 30, + db: Optional[AsyncSession] = None, + ) -> CalendarEventListResponse: + async with get_async_db_context(db) as db: + user_groups = await Groups.get_groups_by_member_id(user_id, db=db) + user_group_ids = [g.id for g in user_groups] + + # Get accessible calendar IDs + cal_stmt = select(Calendar.id) + cal_stmt = AccessGrants.has_permission_filter( + db=db, + query=cal_stmt, + DocumentModel=Calendar, + filter={'user_id': user_id, 'group_ids': user_group_ids}, + resource_type='calendar', + permission='read', + ) + cal_result = await db.execute(cal_stmt) + accessible_cal_ids = [r[0] for r in cal_result.all()] + if not accessible_cal_ids: + return CalendarEventListResponse(items=[], total=0) + + stmt = ( + select(CalendarEvent, User) + .outerjoin(User, User.id == CalendarEvent.user_id) + .filter( + CalendarEvent.is_cancelled == False, + CalendarEvent.calendar_id.in_(accessible_cal_ids), + ) + ) + + if query: + search = f'%{query}%' + stmt = stmt.filter( + or_( + CalendarEvent.title.ilike(search), + CalendarEvent.description.ilike(search), + CalendarEvent.location.ilike(search), + ) + ) + + stmt = stmt.order_by(CalendarEvent.start_at.desc()) + + count_result = await db.execute(select(func.count()).select_from(stmt.subquery())) + total = count_result.scalar() + + if skip: + stmt = stmt.offset(skip) + if limit: + stmt = stmt.limit(limit) + + result = await db.execute(stmt) + items = result.all() + + if not items: + return CalendarEventListResponse(items=[], total=total) + + # Batch-load attendees + event_ids = [event.id for event, _user in items] + att_result = await db.execute( + select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id.in_(event_ids)) + ) + att_rows = att_result.scalars().all() + att_map: dict[str, list[CalendarEventAttendeeModel]] = {} + for a in att_rows: + att_map.setdefault(a.event_id, []).append(CalendarEventAttendeeModel.model_validate(a)) + + events = [] + for event, user in items: + event_data = CalendarEventModel.model_validate(event).model_dump(exclude={'attendees'}) + event_data['attendees'] = att_map.get(event.id, []) + events.append( + CalendarEventUserResponse( + **event_data, + user=(UserResponse(**UserModel.model_validate(user).model_dump()) if user else None), + ) + ) + + return CalendarEventListResponse(items=events, total=total) + + async def update_event_by_id( + self, id: str, form_data: CalendarEventUpdateForm, db: Optional[AsyncSession] = None + ) -> Optional[CalendarEventModel]: + async with get_async_db_context(db) as db: + result = await db.execute(select(CalendarEvent).filter(CalendarEvent.id == id)) + event = result.scalars().first() + if not event: + return None + + update_data = form_data.model_dump(exclude_unset=True) + for field in [ + 'calendar_id', + 'title', + 'description', + 'start_at', + 'end_at', + 'all_day', + 'rrule', + 'color', + 'location', + 'is_cancelled', + ]: + if field in update_data: + setattr(event, field, update_data[field]) + + if 'data' in update_data and update_data['data'] is not None: + event.data = {**(event.data or {}), **update_data['data']} + if 'meta' in update_data and update_data['meta'] is not None: + event.meta = {**(event.meta or {}), **update_data['meta']} + + if 'attendees' in update_data and update_data['attendees'] is not None: + await CalendarEventAttendees.set_attendees(id, update_data['attendees'], db=db) + + event.updated_at = int(time.time_ns()) + await db.commit() + return await self._to_event_model(event, db=db) + + async def get_upcoming_events( + self, + now_ns: int, + default_lookahead_ns: int, + db: Optional[AsyncSession] = None, + ) -> list[tuple[CalendarEventModel, Optional[str]]]: + """Events starting between now and now + lookahead, for alert processing. + + Per-event lookahead is read from meta.alert_minutes (falls back to + default_lookahead_ns). Returns (event, user_timezone) pairs. + """ + from open_webui.models.users import User as UserRow + + # Use the maximum possible lookahead (60 min) to cast a wide net; + # per-event filtering happens in Python after fetching. + max_lookahead_ns = max(default_lookahead_ns, 60 * 60 * 1_000_000_000) + upper = now_ns + max_lookahead_ns + + async with get_async_db_context(db) as db: + result = await db.execute( + select(CalendarEvent, UserRow.timezone) + .outerjoin(UserRow, UserRow.id == CalendarEvent.user_id) + .filter( + CalendarEvent.is_cancelled == False, + CalendarEvent.start_at >= now_ns, + CalendarEvent.start_at <= upper, + ) + ) + rows = result.all() + + events = [] + for event, tz in rows: + model = CalendarEventModel.model_validate(event) + # Determine per-event alert window + alert_minutes = None + if model.meta and 'alert_minutes' in model.meta: + alert_minutes = model.meta['alert_minutes'] + + if alert_minutes is not None: + if alert_minutes < 0: + # alert_minutes < 0 means "no alert" + continue + event_lookahead_ns = alert_minutes * 60 * 1_000_000_000 + else: + event_lookahead_ns = default_lookahead_ns + + if model.start_at <= now_ns + event_lookahead_ns: + events.append((model, tz)) + + return events + + async def delete_event_by_id(self, id: str, db: Optional[AsyncSession] = None) -> bool: + try: + async with get_async_db_context(db) as db: + await db.execute(delete(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == id)) + await db.execute(delete(CalendarEvent).filter(CalendarEvent.id == id)) + await db.commit() + return True + except Exception: + return False + + +class CalendarEventAttendeeTable: + async def set_attendees( + self, event_id: str, attendees: list[dict], db: Optional[AsyncSession] = None + ) -> list[CalendarEventAttendeeModel]: + """Replace all attendees for an event. + + Each dict in attendees: {user_id: str, status?: str, meta?: dict} + """ + async with get_async_db_context(db) as db: + # Remove existing + await db.execute(delete(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id)) + + now = int(time.time_ns()) + models = [] + for att in attendees: + row = CalendarEventAttendee( + id=str(uuid4()), + event_id=event_id, + user_id=att['user_id'], + status=att.get('status', 'pending'), + meta=att.get('meta'), + created_at=now, + updated_at=now, + ) + db.add(row) + models.append(CalendarEventAttendeeModel.model_validate(row)) + + await db.commit() + return models + + async def update_rsvp( + self, event_id: str, user_id: str, status: str, db: Optional[AsyncSession] = None + ) -> Optional[CalendarEventAttendeeModel]: + async with get_async_db_context(db) as db: + result = await db.execute( + select(CalendarEventAttendee).filter( + CalendarEventAttendee.event_id == event_id, + CalendarEventAttendee.user_id == user_id, + ) + ) + att = result.scalars().first() + if not att: + return None + + att.status = status + att.updated_at = int(time.time_ns()) + await db.commit() + return CalendarEventAttendeeModel.model_validate(att) + + async def get_attendees_by_event( + self, event_id: str, db: Optional[AsyncSession] = None + ) -> list[CalendarEventAttendeeModel]: + async with get_async_db_context(db) as db: + result = await db.execute(select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id)) + return [CalendarEventAttendeeModel.model_validate(r) for r in result.scalars().all()] + + async def get_events_by_attendee(self, user_id: str, db: Optional[AsyncSession] = None) -> list[str]: + """Return event IDs where user is an attendee.""" + async with get_async_db_context(db) as db: + result = await db.execute( + select(CalendarEventAttendee.event_id).filter(CalendarEventAttendee.user_id == user_id) + ) + return [r[0] for r in result.all()] + + +Calendars = CalendarTable() +CalendarEvents = CalendarEventTable() +CalendarEventAttendees = CalendarEventAttendeeTable() diff --git a/backend/open_webui/models/chat_messages.py b/backend/open_webui/models/chat_messages.py index bd9c720fa4..0758e0354d 100644 --- a/backend/open_webui/models/chat_messages.py +++ b/backend/open_webui/models/chat_messages.py @@ -313,7 +313,6 @@ class ChatMessageTable: stmt = select(ChatMessage.model_id, func.count(ChatMessage.id).label('count')).filter( ChatMessage.role == 'assistant', ChatMessage.model_id.isnot(None), - ~ChatMessage.user_id.like('shared-%'), ) if start_date: @@ -368,7 +367,6 @@ class ChatMessageTable: ChatMessage.role == 'assistant', ChatMessage.model_id.isnot(None), ChatMessage.usage.isnot(None), - ~ChatMessage.user_id.like('shared-%'), ) if start_date: @@ -430,7 +428,6 @@ class ChatMessageTable: ChatMessage.role == 'assistant', ChatMessage.user_id.isnot(None), ChatMessage.usage.isnot(None), - ~ChatMessage.user_id.like('shared-%'), ) if start_date: @@ -465,7 +462,7 @@ class ChatMessageTable: from open_webui.models.groups import GroupMember stmt = select(ChatMessage.user_id, func.count(ChatMessage.id).label('count')).filter( - ~ChatMessage.user_id.like('shared-%') + ChatMessage.role == 'assistant', ) if start_date: @@ -491,7 +488,7 @@ class ChatMessageTable: from open_webui.models.groups import GroupMember stmt = select(ChatMessage.chat_id, func.count(ChatMessage.id).label('count')).filter( - ~ChatMessage.user_id.like('shared-%') + ChatMessage.role == 'assistant', ) if start_date: @@ -521,7 +518,6 @@ class ChatMessageTable: stmt = select(ChatMessage.created_at, ChatMessage.model_id).filter( ChatMessage.role == 'assistant', ChatMessage.model_id.isnot(None), - ~ChatMessage.user_id.like('shared-%'), ) if start_date: @@ -568,7 +564,6 @@ class ChatMessageTable: stmt = select(ChatMessage.created_at, ChatMessage.model_id).filter( ChatMessage.role == 'assistant', ChatMessage.model_id.isnot(None), - ~ChatMessage.user_id.like('shared-%'), ) if start_date: diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index 3bcfdce03f..ba6611a811 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -555,77 +555,51 @@ class ChatTable: async def insert_shared_chat_by_chat_id( self, chat_id: str, db: Optional[AsyncSession] = None ) -> Optional[ChatModel]: + """Create a shared snapshot for a chat. Returns the original chat with share_id set.""" + from open_webui.models.shared_chats import SharedChats + async with get_async_db_context(db) as db: - # Get the existing chat to share chat = await db.get(Chat, chat_id) - # Check if chat exists if not chat: return None - # Check if the chat is already shared - if chat.share_id: - return await self.get_chat_by_id_and_user_id(chat.share_id, 'shared', db=db) - # Create a new chat with the same data, but with a new ID - shared_chat = ChatModel( - **{ - 'id': str(uuid.uuid4()), - 'user_id': f'shared-{chat_id}', - 'title': chat.title, - 'chat': chat.chat, - 'meta': chat.meta, - 'pinned': chat.pinned, - 'folder_id': chat.folder_id, - 'created_at': chat.created_at, - 'updated_at': int(time.time()), - } - ) - shared_result = Chat(**shared_chat.model_dump()) - db.add(shared_result) - await db.commit() - await db.refresh(shared_result) - # Update the original chat with the share_id - await db.execute(update(Chat).filter_by(id=chat_id).values(share_id=shared_chat.id)) + # If already shared, just update the existing snapshot + if chat.share_id: + return await self.update_shared_chat_by_chat_id(chat_id, db=db) + + shared = await SharedChats.create(chat_id, chat.user_id, db=db) + if not shared: + return None + + # Set share_id on the original chat + chat.share_id = shared.id await db.commit() - return shared_chat if shared_result else None + await db.refresh(chat) + return ChatModel.model_validate(chat) async def update_shared_chat_by_chat_id( self, chat_id: str, db: Optional[AsyncSession] = None ) -> Optional[ChatModel]: + """Re-snapshot the shared chat with current chat data.""" + from open_webui.models.shared_chats import SharedChats + try: async with get_async_db_context(db) as db: chat = await db.get(Chat, chat_id) - result = await db.execute(select(Chat).filter_by(user_id=f'shared-{chat_id}')) - shared_chat = result.scalars().first() - - if shared_chat is None: + if not chat or not chat.share_id: return await self.insert_shared_chat_by_chat_id(chat_id, db=db) - shared_chat.title = chat.title - shared_chat.chat = chat.chat - shared_chat.meta = chat.meta - shared_chat.pinned = chat.pinned - shared_chat.folder_id = chat.folder_id - shared_chat.updated_at = int(time.time()) - await db.commit() - await db.refresh(shared_chat) - - return ChatModel.model_validate(shared_chat) + await SharedChats.update(chat.share_id, db=db) + return ChatModel.model_validate(chat) except Exception: return None async def delete_shared_chat_by_chat_id(self, chat_id: str, db: Optional[AsyncSession] = None) -> bool: + """Delete shared snapshot for a chat.""" + from open_webui.models.shared_chats import SharedChats + try: - async with get_async_db_context(db) as db: - # Get shared chat IDs - result = await db.execute(select(Chat.id).filter_by(user_id=f'shared-{chat_id}')) - shared_ids = [row[0] for row in result.all()] - - if shared_ids: - await db.execute(delete(ChatMessage).filter(ChatMessage.chat_id.in_(shared_ids))) - await db.execute(delete(Chat).filter_by(user_id=f'shared-{chat_id}')) - await db.commit() - - return True + return await SharedChats.delete_by_chat_id(chat_id, db=db) except Exception: return False @@ -746,53 +720,10 @@ class ChatTable: limit: int = 50, db: Optional[AsyncSession] = None, ) -> list[SharedChatResponse]: - async with get_async_db_context(db) as db: - stmt = ( - select(Chat.id, Chat.title, Chat.share_id, Chat.updated_at, Chat.created_at) - .filter_by(user_id=user_id) - .filter(Chat.share_id.isnot(None)) - ) + """Delegate to SharedChats for listing shared chats by user.""" + from open_webui.models.shared_chats import SharedChats - if filter: - query_key = filter.get('query') - if query_key: - stmt = stmt.filter(Chat.title.ilike(f'%{query_key}%')) - - order_by = filter.get('order_by') - direction = filter.get('direction') - - if order_by and direction: - if not getattr(Chat, order_by, None): - raise ValueError('Invalid order_by field') - - if direction.lower() == 'asc': - stmt = stmt.order_by(getattr(Chat, order_by).asc(), Chat.id) - elif direction.lower() == 'desc': - stmt = stmt.order_by(getattr(Chat, order_by).desc(), Chat.id) - else: - raise ValueError('Invalid direction for ordering') - else: - stmt = stmt.order_by(Chat.updated_at.desc(), Chat.id) - - if skip: - stmt = stmt.offset(skip) - if limit: - stmt = stmt.limit(limit) - - result = await db.execute(stmt) - all_chats = result.all() - return [ - SharedChatResponse.model_validate( - { - 'id': chat[0], - 'title': chat[1], - 'share_id': chat[2], - 'updated_at': chat[3], - 'created_at': chat[4], - } - ) - for chat in all_chats - ] + return await SharedChats.get_by_user_id(user_id, filter=filter, skip=skip, limit=limit, db=db) async def get_chat_list_by_user_id( self, @@ -925,15 +856,23 @@ class ChatTable: return None async def get_chat_by_share_id(self, id: str, db: Optional[AsyncSession] = None) -> Optional[ChatModel]: - try: - async with get_async_db_context(db) as db: - result = await db.execute(select(Chat).filter_by(share_id=id)) - chat = result.scalars().first() + """Look up a shared chat snapshot by its share token.""" + from open_webui.models.shared_chats import SharedChats - if chat: - return await self.get_chat_by_id(id, db=db) - else: - return None + try: + shared = await SharedChats.get_by_id(id, db=db) + if shared: + # Return a ChatModel-compatible view of the snapshot + return ChatModel( + id=shared.id, + user_id=shared.user_id, + title=shared.title, + chat=shared.chat, + created_at=shared.created_at, + updated_at=shared.updated_at, + share_id=shared.id, + ) + return None except Exception: return None @@ -1323,8 +1262,10 @@ class ChatTable: self, id: str, user_id: str, db: Optional[AsyncSession] = None ) -> list[TagModel]: async with get_async_db_context(db) as db: - chat = await db.get(Chat, id) - tag_ids = chat.meta.get('tags', []) + stmt = select(Chat.meta).where(Chat.id == id) + result = await db.execute(stmt) + meta = result.scalar_one_or_none() + tag_ids = (meta or {}).get('tags', []) return await Tags.get_tags_by_ids_and_user_id(tag_ids, user_id, db=db) async def get_chat_list_by_user_id_and_tag_name( @@ -1568,20 +1509,17 @@ class ChatTable: return False async def delete_shared_chats_by_user_id(self, user_id: str, db: Optional[AsyncSession] = None) -> bool: + """Delete all shared chat snapshots created by a user.""" + from open_webui.models.shared_chats import SharedChats, SharedChat as SharedChatTable + try: async with get_async_db_context(db) as db: - result = await db.execute(select(Chat.id).filter_by(user_id=user_id)) - id_rows = result.all() - shared_chat_ids = [f'shared-{row[0]}' for row in id_rows] + # Delete shared_chat rows for this user's chats + await db.execute(delete(SharedChatTable).filter_by(user_id=user_id)) - if shared_chat_ids: - # Get shared chat IDs to delete associated messages - shared_result = await db.execute(select(Chat.id).filter(Chat.user_id.in_(shared_chat_ids))) - shared_ids = [row[0] for row in shared_result.all()] - if shared_ids: - await db.execute(delete(ChatMessage).filter(ChatMessage.chat_id.in_(shared_ids))) - await db.execute(delete(Chat).filter(Chat.user_id.in_(shared_chat_ids))) - await db.commit() + # Clear share_id on all of this user's chats + await db.execute(update(Chat).filter_by(user_id=user_id).values(share_id=None)) + await db.commit() return True except Exception: @@ -1598,11 +1536,11 @@ class ChatTable: if not file_ids: return None - chat_message_file_ids = [ + chat_message_file_ids = { item.id for item in await self.get_chat_files_by_chat_id_and_message_id(chat_id, message_id, db=db) - ] + } # Remove duplicates and existing file_ids - file_ids = list(set([file_id for file_id in file_ids if file_id and file_id not in chat_message_file_ids])) + file_ids = list({file_id for file_id in file_ids if file_id and file_id not in chat_message_file_ids}) if not file_ids: return None @@ -1651,16 +1589,15 @@ class ChatTable: except Exception: return False - async def get_shared_chats_by_file_id(self, file_id: str, db: Optional[AsyncSession] = None) -> list[ChatModel]: + async def get_shared_chat_ids_by_file_id(self, file_id: str, db: Optional[AsyncSession] = None) -> list[str]: + """Return IDs of chats that contain this file and have an active share link.""" async with get_async_db_context(db) as db: result = await db.execute( - select(Chat) + select(Chat.id) .join(ChatFile, Chat.id == ChatFile.chat_id) .filter(ChatFile.file_id == file_id, Chat.share_id.isnot(None)) ) - all_chats = result.scalars().all() - - return [ChatModel.model_validate(chat) for chat in all_chats] + return [row[0] for row in result.all()] async def update_chat_tasks_by_id(self, id: str, tasks: list[dict]) -> Optional[ChatModel]: """Update the tasks list on a chat.""" diff --git a/backend/open_webui/models/prompts.py b/backend/open_webui/models/prompts.py index fbf5401203..dec1848aa7 100644 --- a/backend/open_webui/models/prompts.py +++ b/backend/open_webui/models/prompts.py @@ -3,7 +3,7 @@ import time import uuid from typing import Optional -from sqlalchemy import select, delete, update, or_, func, cast, String +from sqlalchemy import select, delete, update, or_, func, text, cast, String from sqlalchemy.ext.asyncio import AsyncSession from open_webui.internal.db import Base, JSONField, get_async_db_context from open_webui.models.groups import Groups @@ -260,12 +260,12 @@ class PromptsTable: ) -> PromptListResponse: async with get_async_db_context(db) as db: # Join with User table for user filtering and sorting - stmt = select(Prompt, User).outerjoin(User, User.id == Prompt.user_id) + query = select(Prompt, User).outerjoin(User, User.id == Prompt.user_id) if filter: query_key = filter.get('query') if query_key: - stmt = stmt.filter( + query = query.filter( or_( Prompt.name.ilike(f'%{query_key}%'), Prompt.command.ilike(f'%{query_key}%'), @@ -277,14 +277,14 @@ class PromptsTable: view_option = filter.get('view_option') if view_option == 'created': - stmt = stmt.filter(Prompt.user_id == user_id) + query = query.filter(Prompt.user_id == user_id) elif view_option == 'shared': - stmt = stmt.filter(Prompt.user_id != user_id) + query = query.filter(Prompt.user_id != user_id) # Apply access grant filtering - stmt = AccessGrants.has_permission_filter( + query = AccessGrants.has_permission_filter( db=db, - query=stmt, + query=query, DocumentModel=Prompt, filter=filter, resource_type='prompt', @@ -293,56 +293,63 @@ class PromptsTable: tag = filter.get('tag') if tag: - # SQLite stores JSON text via json.dumps(ensure_ascii=True), - # so non-ASCII chars are \uXXXX-escaped. PostgreSQL native JSONB - # stores literal Unicode. Use the right pattern for each. - if db.bind.dialect.name == 'sqlite': - if tag.isascii(): - tags_text = func.lower(cast(Prompt.tags, String)) - pattern = f'%{json.dumps(tag.lower())}%' - else: - # LOWER() is ASCII-only; non-ASCII codepoints would - # produce different \uXXXX escapes when lowered. - tags_text = cast(Prompt.tags, String) - pattern = f'%{json.dumps(tag)}%' + bind = await db.connection() + dialect_name = bind.dialect.name + tag_lower = tag.lower() + + if dialect_name == 'sqlite': + tag_clause = text( + 'EXISTS (SELECT 1 FROM json_each(prompt.tags) t WHERE LOWER(t.value) = :tag_val)' + ) + elif dialect_name == 'postgresql': + tag_clause = text( + 'EXISTS (SELECT 1 FROM json_array_elements_text(prompt.tags) t WHERE LOWER(t) = :tag_val)' + ) else: - tags_text = func.lower(cast(Prompt.tags, String)) - pattern = f'%{json.dumps(tag.lower(), ensure_ascii=False)}%' - stmt = stmt.filter(tags_text.like(pattern)) + # Fallback: LIKE on serialised JSON text (ASCII-safe only) + tag_clause = func.lower(cast(Prompt.tags, String)).like( + f'%{json.dumps(tag_lower, ensure_ascii=False)}%' + ) + tag_lower = None + + if tag_lower is not None: + query = query.filter(tag_clause.params(tag_val=tag_lower)) + else: + query = query.filter(tag_clause) order_by = filter.get('order_by') direction = filter.get('direction') if order_by == 'name': if direction == 'asc': - stmt = stmt.order_by(Prompt.name.asc()) + query = query.order_by(Prompt.name.asc()) else: - stmt = stmt.order_by(Prompt.name.desc()) + query = query.order_by(Prompt.name.desc()) elif order_by == 'created_at': if direction == 'asc': - stmt = stmt.order_by(Prompt.created_at.asc()) + query = query.order_by(Prompt.created_at.asc()) else: - stmt = stmt.order_by(Prompt.created_at.desc()) + query = query.order_by(Prompt.created_at.desc()) elif order_by == 'updated_at': if direction == 'asc': - stmt = stmt.order_by(Prompt.updated_at.asc()) + query = query.order_by(Prompt.updated_at.asc()) else: - stmt = stmt.order_by(Prompt.updated_at.desc()) + query = query.order_by(Prompt.updated_at.desc()) else: - stmt = stmt.order_by(Prompt.updated_at.desc()) + query = query.order_by(Prompt.updated_at.desc()) else: - stmt = stmt.order_by(Prompt.updated_at.desc()) + query = query.order_by(Prompt.updated_at.desc()) # Count BEFORE pagination - count_result = await db.execute(select(func.count()).select_from(stmt.subquery())) + count_result = await db.execute(select(func.count()).select_from(query.subquery())) total = count_result.scalar() if skip: - stmt = stmt.offset(skip) + query = query.offset(skip) if limit: - stmt = stmt.limit(limit) + query = query.limit(limit) - result = await db.execute(stmt) + result = await db.execute(query) items = result.all() prompt_ids = [prompt.id for prompt, _ in items] diff --git a/backend/open_webui/models/shared_chats.py b/backend/open_webui/models/shared_chats.py new file mode 100644 index 0000000000..37a3fea852 --- /dev/null +++ b/backend/open_webui/models/shared_chats.py @@ -0,0 +1,207 @@ +import logging +import time +import uuid +from typing import Optional + +from sqlalchemy import select, delete +from sqlalchemy.ext.asyncio import AsyncSession +from open_webui.internal.db import Base, JSONField, get_async_db_context + +from pydantic import BaseModel, ConfigDict +from sqlalchemy import BigInteger, Column, ForeignKey, Text, JSON + +log = logging.getLogger(__name__) + +#################### +# SharedChat DB Schema +#################### + + +class SharedChat(Base): + __tablename__ = 'shared_chat' + + id = Column(Text, primary_key=True) # The share token (UUID) — used in /s/{id} URL + chat_id = Column(Text, ForeignKey('chat.id', ondelete='CASCADE'), nullable=False) + user_id = Column(Text, nullable=False) # Who created this share + + title = Column(Text) + chat = Column(JSON) # Snapshot of chat JSON at share time + + created_at = Column(BigInteger) + updated_at = Column(BigInteger) + + +class SharedChatModel(BaseModel): + model_config = ConfigDict(from_attributes=True) + + id: str + chat_id: str + user_id: str + + title: str + chat: dict + + created_at: int + updated_at: int + + +class SharedChatResponse(BaseModel): + id: str + chat_id: str + title: str + share_id: Optional[str] = None # Alias for id, for backward compat + updated_at: int + created_at: int + + +#################### +# Table Operations +#################### + + +class SharedChatsTable: + async def create(self, chat_id: str, user_id: str, db: Optional[AsyncSession] = None) -> Optional[SharedChatModel]: + """ + Create a snapshot of the chat for link sharing. + Returns the SharedChatModel with the share token as its id. + """ + async with get_async_db_context(db) as db: + from open_webui.models.chats import Chat + + chat = await db.get(Chat, chat_id) + if not chat: + return None + + share_id = str(uuid.uuid4()) + now = int(time.time()) + + shared_chat = SharedChat( + id=share_id, + chat_id=chat_id, + user_id=user_id, + title=chat.title, + chat=chat.chat, + created_at=now, + updated_at=now, + ) + db.add(shared_chat) + await db.commit() + await db.refresh(shared_chat) + + return SharedChatModel.model_validate(shared_chat) + + async def update(self, share_id: str, db: Optional[AsyncSession] = None) -> Optional[SharedChatModel]: + """ + Re-snapshot: update the shared chat with the current state of the original chat. + """ + async with get_async_db_context(db) as db: + from open_webui.models.chats import Chat + + shared_chat = await db.get(SharedChat, share_id) + if not shared_chat: + return None + + chat = await db.get(Chat, shared_chat.chat_id) + if not chat: + return None + + shared_chat.title = chat.title + shared_chat.chat = chat.chat + shared_chat.updated_at = int(time.time()) + + await db.commit() + await db.refresh(shared_chat) + return SharedChatModel.model_validate(shared_chat) + + async def get_by_id(self, share_id: str, db: Optional[AsyncSession] = None) -> Optional[SharedChatModel]: + """Get a shared chat by its share token.""" + async with get_async_db_context(db) as db: + shared_chat = await db.get(SharedChat, share_id) + if shared_chat: + return SharedChatModel.model_validate(shared_chat) + return None + + async def get_by_chat_id(self, chat_id: str, db: Optional[AsyncSession] = None) -> Optional[SharedChatModel]: + """Get the shared chat for a given original chat. Returns the most recent one.""" + async with get_async_db_context(db) as db: + result = await db.execute( + select(SharedChat).filter_by(chat_id=chat_id).order_by(SharedChat.updated_at.desc()).limit(1) + ) + shared_chat = result.scalars().first() + if shared_chat: + return SharedChatModel.model_validate(shared_chat) + return None + + async def get_by_user_id( + self, + user_id: str, + filter: Optional[dict] = None, + skip: int = 0, + limit: int = 50, + db: Optional[AsyncSession] = None, + ) -> list[SharedChatResponse]: + """List all shared chats created by a user.""" + async with get_async_db_context(db) as db: + stmt = select(SharedChat).filter_by(user_id=user_id) + + if filter: + query_key = filter.get('query') + if query_key: + stmt = stmt.filter(SharedChat.title.ilike(f'%{query_key}%')) + + order_by = filter.get('order_by') + direction = filter.get('direction') + + if order_by and direction: + col = getattr(SharedChat, order_by, None) + if not col: + raise ValueError('Invalid order_by field') + if direction.lower() == 'asc': + stmt = stmt.order_by(col.asc()) + elif direction.lower() == 'desc': + stmt = stmt.order_by(col.desc()) + else: + raise ValueError('Invalid direction for ordering') + else: + stmt = stmt.order_by(SharedChat.updated_at.desc()) + + if skip: + stmt = stmt.offset(skip) + if limit: + stmt = stmt.limit(limit) + + result = await db.execute(stmt) + return [ + SharedChatResponse( + id=sc.chat_id, + chat_id=sc.chat_id, + title=sc.title, + share_id=sc.id, + updated_at=sc.updated_at, + created_at=sc.created_at, + ) + for sc in result.scalars().all() + ] + + async def delete_by_id(self, share_id: str, db: Optional[AsyncSession] = None) -> bool: + """Delete a shared chat by its share token.""" + try: + async with get_async_db_context(db) as db: + await db.execute(delete(SharedChat).filter_by(id=share_id)) + await db.commit() + return True + except Exception: + return False + + async def delete_by_chat_id(self, chat_id: str, db: Optional[AsyncSession] = None) -> bool: + """Delete all shared chats for a given original chat.""" + try: + async with get_async_db_context(db) as db: + await db.execute(delete(SharedChat).filter_by(chat_id=chat_id)) + await db.commit() + return True + except Exception: + return False + + +SharedChats = SharedChatsTable() diff --git a/backend/open_webui/retrieval/loaders/mistral.py b/backend/open_webui/retrieval/loaders/mistral.py index 71c7f10812..51681ad5dc 100644 --- a/backend/open_webui/retrieval/loaders/mistral.py +++ b/backend/open_webui/retrieval/loaders/mistral.py @@ -10,7 +10,7 @@ from typing import List, Dict, Any from contextlib import asynccontextmanager from langchain_core.documents import Document -from open_webui.env import GLOBAL_LOG_LEVEL +from open_webui.env import GLOBAL_LOG_LEVEL, AIOHTTP_CLIENT_SESSION_SSL logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL) log = logging.getLogger(__name__) @@ -292,6 +292,7 @@ class MistralLoader: data=writer, headers=self.headers, timeout=aiohttp.ClientTimeout(total=self.upload_timeout), + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: return await self._handle_response_async(response) @@ -340,6 +341,7 @@ class MistralLoader: headers=headers, params=params, timeout=aiohttp.ClientTimeout(total=self.url_timeout), + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: return await self._handle_response_async(response) @@ -411,6 +413,7 @@ class MistralLoader: json=payload, headers=headers, timeout=aiohttp.ClientTimeout(total=self.ocr_timeout), + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: ocr_response = await self._handle_response_async(response) @@ -533,7 +536,8 @@ class MistralLoader: async with session.delete( url=f'{self.base_url}/files/{file_id}', headers=self.headers, - timeout=aiohttp.ClientTimeout(total=self.cleanup_timeout), # Shorter timeout for cleanup + timeout=aiohttp.ClientTimeout(total=self.cleanup_timeout), + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: return await self._handle_response_async(response) diff --git a/backend/open_webui/retrieval/models/colbert.py b/backend/open_webui/retrieval/models/colbert.py index d122291ec5..ceb41824e3 100644 --- a/backend/open_webui/retrieval/models/colbert.py +++ b/backend/open_webui/retrieval/models/colbert.py @@ -59,14 +59,14 @@ class ColBERT(BaseReranker): return normalized_scores.detach().cpu().numpy().astype(np.float32) - def predict(self, sentences): + def predict(self, sentences, batch_size=32): query = sentences[0][0] docs = [i[1] for i in sentences] # Embedding the documents - embedded_docs = self.ckpt.docFromText(docs, bsize=32)[0] + embedded_docs = self.ckpt.docFromText(docs, bsize=batch_size)[0] # Embedding the queries - embedded_queries = self.ckpt.queryFromText([query], bsize=32) + embedded_queries = self.ckpt.queryFromText([query], bsize=batch_size) embedded_query = embedded_queries[0] # Calculate retrieval scores for the query against all documents diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index 3638409eee..fb5a46c2b0 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -83,11 +83,123 @@ def get_loader(request, url: str): ) +def build_loader_from_config(request): + """Build a Loader instance with the admin's configured extraction engine settings.""" + from open_webui.retrieval.loaders.main import Loader + + config = request.app.state.config + return Loader( + engine=config.CONTENT_EXTRACTION_ENGINE, + DATALAB_MARKER_API_KEY=config.DATALAB_MARKER_API_KEY, + DATALAB_MARKER_API_BASE_URL=config.DATALAB_MARKER_API_BASE_URL, + DATALAB_MARKER_ADDITIONAL_CONFIG=config.DATALAB_MARKER_ADDITIONAL_CONFIG, + DATALAB_MARKER_SKIP_CACHE=config.DATALAB_MARKER_SKIP_CACHE, + DATALAB_MARKER_FORCE_OCR=config.DATALAB_MARKER_FORCE_OCR, + DATALAB_MARKER_PAGINATE=config.DATALAB_MARKER_PAGINATE, + DATALAB_MARKER_STRIP_EXISTING_OCR=config.DATALAB_MARKER_STRIP_EXISTING_OCR, + DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION=config.DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION, + DATALAB_MARKER_FORMAT_LINES=config.DATALAB_MARKER_FORMAT_LINES, + DATALAB_MARKER_USE_LLM=config.DATALAB_MARKER_USE_LLM, + DATALAB_MARKER_OUTPUT_FORMAT=config.DATALAB_MARKER_OUTPUT_FORMAT, + EXTERNAL_DOCUMENT_LOADER_URL=config.EXTERNAL_DOCUMENT_LOADER_URL, + EXTERNAL_DOCUMENT_LOADER_API_KEY=config.EXTERNAL_DOCUMENT_LOADER_API_KEY, + TIKA_SERVER_URL=config.TIKA_SERVER_URL, + DOCLING_SERVER_URL=config.DOCLING_SERVER_URL, + DOCLING_API_KEY=config.DOCLING_API_KEY, + DOCLING_PARAMS=config.DOCLING_PARAMS, + PDF_EXTRACT_IMAGES=config.PDF_EXTRACT_IMAGES, + PDF_LOADER_MODE=config.PDF_LOADER_MODE, + DOCUMENT_INTELLIGENCE_ENDPOINT=config.DOCUMENT_INTELLIGENCE_ENDPOINT, + DOCUMENT_INTELLIGENCE_KEY=config.DOCUMENT_INTELLIGENCE_KEY, + DOCUMENT_INTELLIGENCE_MODEL=config.DOCUMENT_INTELLIGENCE_MODEL, + MISTRAL_OCR_API_BASE_URL=config.MISTRAL_OCR_API_BASE_URL, + MISTRAL_OCR_API_KEY=config.MISTRAL_OCR_API_KEY, + MINERU_API_MODE=config.MINERU_API_MODE, + MINERU_API_URL=config.MINERU_API_URL, + MINERU_API_KEY=config.MINERU_API_KEY, + MINERU_API_TIMEOUT=config.MINERU_API_TIMEOUT, + MINERU_PARAMS=config.MINERU_PARAMS, + ) + + +def _extract_text_from_binary_response(request, response: requests.Response, url: str) -> tuple[str, list]: + """Download response body to a temp file and extract text using the Loader pipeline.""" + import mimetypes + import tempfile + import urllib.parse + + content_type = response.headers.get('Content-Type', '').split(';')[0].strip() + + # Derive filename from URL path, falling back to Content-Disposition or mime guess + url_path = urllib.parse.urlparse(url).path + filename = os.path.basename(url_path) if url_path else '' + + if not filename or '.' not in filename: + # Try Content-Disposition header + cd = response.headers.get('Content-Disposition', '') + if 'filename=' in cd: + filename = cd.split('filename=')[-1].strip('"\'') + + if not filename or '.' not in filename: + ext = mimetypes.guess_extension(content_type) or '' + filename = f'download{ext}' + + suffix = '.' + filename.split('.')[-1].lower() if '.' in filename else '' + + with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp: + tmp.write(response.content) + tmp_path = tmp.name + + try: + loader = build_loader_from_config(request) + docs = loader.load(filename, content_type, tmp_path) + for doc in docs: + doc.metadata['source'] = url + content = ' '.join([doc.page_content for doc in docs]) + return content, docs + finally: + os.remove(tmp_path) + + +def _is_text_content_type(content_type: str) -> bool: + """Return True if the content type should be handled by the web loader.""" + ct = content_type.split(';')[0].strip().lower() + if ct.startswith('text/'): + return True + if any(t in ct for t in ['xml', 'json', 'javascript']): + return True + return not ct # empty / missing → assume HTML + + def get_content_from_url(request, url: str) -> str: - loader = get_loader(request, url) - docs = loader.load() - content = ' '.join([doc.page_content for doc in docs]) - return content, docs + from open_webui.retrieval.web.utils import validate_url + + # Validate URL before making any request (blocks private IPs, non-HTTP, filter list) + validate_url(url) + + # Streamed GET to check Content-Type without downloading the body. + try: + response = requests.get(url, stream=True, timeout=30) + response.raise_for_status() + content_type = response.headers.get('Content-Type', '') + except Exception: + content_type = '' + response = None + + # Text / HTML / unknown — use the configured web loader + if response is None or _is_text_content_type(content_type): + if response is not None: + response.close() + loader = get_loader(request, url) + docs = loader.load() + content = ' '.join([doc.page_content for doc in docs]) + return content, docs + + # Binary content (PDF, DOCX, XLSX, PPTX, etc.) — download and extract + try: + return _extract_text_from_binary_response(request, response, url) + finally: + response.close() CHUNK_HASH_KEY = '_chunk_hash' @@ -919,7 +1031,7 @@ async def generate_embeddings( return embeddings[0] if isinstance(text, str) else embeddings -def get_reranking_function(reranking_engine, reranking_model, reranking_function): +def get_reranking_function(reranking_engine, reranking_model, reranking_function, reranking_batch_size=32): if reranking_function is None: return None if reranking_engine == 'external': @@ -928,10 +1040,61 @@ def get_reranking_function(reranking_engine, reranking_model, reranking_function ) else: return lambda query, documents, user=None: reranking_function.predict( - [(query, doc.page_content) for doc in documents] + [(query, doc.page_content) for doc in documents], batch_size=int(reranking_batch_size) ) +async def filter_accessible_collections( + collection_names: set[str], + user: UserModel, + access_type: str = 'read', +) -> set[str]: + """ + Return only the collection names the user is allowed to access. + Admins bypass all checks. For non-admins the policy is: + + - file-* → validated via has_access_to_file + - user-memory-* → must match user's own memory collection + - web-search-* → ephemeral per-query collections, always allowed + - knowledge-bases → always denied (system meta-collection) + - everything else → if the name matches a knowledge base, validated + via Knowledges.check_access_by_user_id; if no + such KB exists, the name is treated as an + ephemeral/legacy collection and allowed + """ + if user.role == 'admin': + return collection_names + + validated = set() + for name in collection_names: + if name == 'knowledge-bases': + # System meta-collection — never exposed to non-admins. + continue + elif name.startswith('file-'): + file_id = name[len('file-') :] + if await has_access_to_file(file_id=file_id, access_type=access_type, user=user): + validated.add(name) + elif name.startswith('user-memory-'): + if name == f'user-memory-{user.id}': + validated.add(name) + elif name.startswith('web-search-'): + # Ephemeral collections created by process_web_search — safe + # to allow because they contain only transient web-search + # results scoped to the requesting user's session. + validated.add(name) + else: + # May be a knowledge-base ID or a legacy/ephemeral collection. + # If it IS a KB, enforce access control. If no such KB + # exists, treat it as a non-sensitive collection (e.g. legacy + # model knowledge, process_text SHA256 collections) and allow. + if await Knowledges.check_access_by_user_id(name, user.id, permission=access_type): + validated.add(name) + elif not await Knowledges.get_knowledge_by_id(name): + # Not a KB at all — legacy/ephemeral collection, allow + validated.add(name) + return validated + + async def get_sources_from_items( request, items, @@ -1147,6 +1310,13 @@ async def get_sources_from_items( log.debug(f'skipping {item} as it has already been extracted') continue + # Filter out collections the user cannot read + if user: + collection_names = await filter_accessible_collections(collection_names, user) + if not collection_names: + log.debug(f'access denied for all collections in item {item}') + continue + try: if full_context: # Sync helper makes blocking VECTOR_DB_CLIENT calls; diff --git a/backend/open_webui/retrieval/web/utils.py b/backend/open_webui/retrieval/web/utils.py index cfe0f71b85..cd5c3a946d 100644 --- a/backend/open_webui/retrieval/web/utils.py +++ b/backend/open_webui/retrieval/web/utils.py @@ -45,6 +45,7 @@ from open_webui.config import ( WEB_FETCH_FILTER_LIST, ) from open_webui.utils.misc import is_string_allowed +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL log = logging.getLogger(__name__) @@ -511,6 +512,8 @@ class SafeWebBaseLoader(WebBaseLoader): ) if not self.session.verify: kwargs['ssl'] = False + else: + kwargs['ssl'] = AIOHTTP_CLIENT_SESSION_SSL async with session.get( url, diff --git a/backend/open_webui/routers/audio.py b/backend/open_webui/routers/audio.py index 499c876261..5260bd873c 100644 --- a/backend/open_webui/routers/audio.py +++ b/backend/open_webui/routers/audio.py @@ -5,7 +5,6 @@ import os import uuid import html import base64 -from functools import lru_cache from pydub import AudioSegment from pydub.silence import split_on_silence from concurrent.futures import ThreadPoolExecutor @@ -421,7 +420,7 @@ async def speech(request: Request, user=Depends(get_verified_user)): elif request.app.state.config.TTS_ENGINE == 'elevenlabs': voice_id = payload.get('voice', '') - if voice_id not in get_available_voices(request): + if voice_id not in await get_available_voices(request): raise HTTPException( status_code=400, detail='Invalid voice id', @@ -975,7 +974,10 @@ def transcription_handler(request, file_path, metadata, user=None): # Read and encode audio file as base64 with open(audio_file_to_use, 'rb') as audio_file: - audio_base64 = base64.b64encode(audio_file.read()).decode('utf-8') + audio_base64 = { + 'data': base64.b64encode(audio_file.read()).decode('utf-8'), + 'format': mimetypes.guess_extension(mimetypes.guess_type(audio_file_to_use)[0]).lstrip('.'), + } # Prepare chat completions request url = f'{api_base_url}/chat/completions' @@ -1292,40 +1294,56 @@ async def transcription( ) -def get_available_models(request: Request) -> list[dict]: +async def get_available_models(request: Request) -> list[dict]: available_models = [] if request.app.state.config.TTS_ENGINE == 'openai': # Use custom endpoint if not using the official OpenAI API URL if not request.app.state.config.TTS_OPENAI_API_BASE_URL.startswith('https://api.openai.com'): - try: - response = requests.get( - f'{request.app.state.config.TTS_OPENAI_API_BASE_URL}/audio/models', - timeout=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST, - ) - response.raise_for_status() - data = response.json() - available_models = data.get('models', []) - except Exception as e: - log.error(f'Error fetching models from custom endpoint: {str(e)}') - available_models = [{'id': 'tts-1'}, {'id': 'tts-1-hd'}] + timeout = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST) + async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: + try: + async with session.get( + f'{request.app.state.config.TTS_OPENAI_API_BASE_URL}/audio/models', + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as response: + response.raise_for_status() + data = await response.json() + available_models = data.get('models', []) + except Exception as e: + log.debug(f'/audio/models not available, trying /models fallback: {str(e)}') + # Fallback to standard OpenAI-compatible /models endpoint + # (used by KokoroTTS and similar custom TTS servers) + try: + async with session.get( + f'{request.app.state.config.TTS_OPENAI_API_BASE_URL}/models', + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as response: + response.raise_for_status() + data = await response.json() + # OpenAI /models returns {"data": [...]}, /audio/models returns {"models": [...]} + available_models = data.get('data', data.get('models', [])) + except Exception as e2: + log.error(f'Error fetching models from custom endpoint: {str(e2)}') + available_models = [{'id': 'tts-1'}, {'id': 'tts-1-hd'}] else: available_models = [{'id': 'tts-1'}, {'id': 'tts-1-hd'}] elif request.app.state.config.TTS_ENGINE == 'elevenlabs': try: - response = requests.get( - f'{ELEVENLABS_API_BASE_URL}/v1/models', - headers={ - 'xi-api-key': request.app.state.config.TTS_API_KEY, - 'Content-Type': 'application/json', - }, - timeout=5, - ) - response.raise_for_status() - models = response.json() - - available_models = [{'name': model['name'], 'id': model['model_id']} for model in models] - except requests.RequestException as e: - log.error(f'Error fetching voices: {str(e)}') + timeout = aiohttp.ClientTimeout(total=5) + async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: + async with session.get( + f'{ELEVENLABS_API_BASE_URL}/v1/models', + headers={ + 'xi-api-key': request.app.state.config.TTS_API_KEY, + 'Content-Type': 'application/json', + }, + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as response: + response.raise_for_status() + models = await response.json() + available_models = [{'name': model['name'], 'id': model['model_id']} for model in models] + except Exception as e: + log.error(f'Error fetching models: {str(e)}') elif request.app.state.config.TTS_ENGINE == 'mistral': available_models = [{'id': 'mistral-tts-latest'}] return available_models @@ -1333,24 +1351,26 @@ def get_available_models(request: Request) -> list[dict]: @router.get('/models') async def get_models(request: Request, user=Depends(get_verified_user)): - return {'models': get_available_models(request)} + return {'models': await get_available_models(request)} -def get_available_voices(request) -> dict: +async def get_available_voices(request) -> dict: """Returns {voice_id: voice_name} dict""" available_voices = {} if request.app.state.config.TTS_ENGINE == 'openai': # Use custom endpoint if not using the official OpenAI API URL if not request.app.state.config.TTS_OPENAI_API_BASE_URL.startswith('https://api.openai.com'): try: - response = requests.get( - f'{request.app.state.config.TTS_OPENAI_API_BASE_URL}/audio/voices', - timeout=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST, - ) - response.raise_for_status() - data = response.json() - voices_list = data.get('voices', []) - available_voices = {voice['id']: voice['name'] for voice in voices_list} + timeout = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST) + async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: + async with session.get( + f'{request.app.state.config.TTS_OPENAI_API_BASE_URL}/audio/voices', + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as response: + response.raise_for_status() + data = await response.json() + voices_list = data.get('voices', []) + available_voices = {voice['id']: voice['name'] for voice in voices_list} except Exception as e: log.error(f'Error fetching voices from custom endpoint: {str(e)}') available_voices = { @@ -1372,7 +1392,7 @@ def get_available_voices(request) -> dict: } elif request.app.state.config.TTS_ENGINE == 'elevenlabs': try: - available_voices = get_elevenlabs_voices(api_key=request.app.state.config.TTS_API_KEY) + available_voices = await get_elevenlabs_voices(api_key=request.app.state.config.TTS_API_KEY) except Exception: # Avoided @lru_cache with exception pass @@ -1383,13 +1403,15 @@ def get_available_voices(request) -> dict: url = (base_url or f'https://{region}.tts.speech.microsoft.com') + '/cognitiveservices/voices/list' headers = {'Ocp-Apim-Subscription-Key': request.app.state.config.TTS_API_KEY} - response = requests.get(url, headers=headers, timeout=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST) - response.raise_for_status() - voices = response.json() + timeout = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST) + async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: + async with session.get(url, headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL) as response: + response.raise_for_status() + voices = await response.json() - for voice in voices: - available_voices[voice['ShortName']] = f'{voice["DisplayName"]} ({voice["ShortName"]})' - except requests.RequestException as e: + for voice in voices: + available_voices[voice['ShortName']] = f'{voice["DisplayName"]} ({voice["ShortName"]})' + except Exception as e: log.error(f'Error fetching voices: {str(e)}') elif request.app.state.config.TTS_ENGINE == 'mistral': api_key = request.app.state.config.TTS_MISTRAL_API_KEY @@ -1397,29 +1419,30 @@ def get_available_voices(request) -> dict: if api_key: try: - response = requests.get( - f'{api_base_url}/audio/voices', - headers={ - 'Authorization': f'Bearer {api_key}', - }, - timeout=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST, - ) - response.raise_for_status() - voices_data = response.json() + timeout = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST) + async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: + async with session.get( + f'{api_base_url}/audio/voices', + headers={ + 'Authorization': f'Bearer {api_key}', + }, + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as response: + response.raise_for_status() + voices_data = await response.json() - for voice in voices_data: - voice_id = voice.get('voice_id', voice.get('id', '')) - voice_name = voice.get('name', voice_id) - if voice_id: - available_voices[voice_id] = voice_name - except requests.RequestException as e: + for voice in voices_data: + voice_id = voice.get('voice_id', voice.get('id', '')) + voice_name = voice.get('name', voice_id) + if voice_id: + available_voices[voice_id] = voice_name + except Exception as e: log.error(f'Error fetching Mistral voices: {str(e)}') return available_voices -@lru_cache -def get_elevenlabs_voices(api_key: str) -> dict: +async def get_elevenlabs_voices(api_key: str) -> dict: """ Note, set the following in your .env file to use Elevenlabs: AUDIO_TTS_ENGINE=elevenlabs @@ -1430,22 +1453,23 @@ def get_elevenlabs_voices(api_key: str) -> dict: try: # TODO: Add retries - response = requests.get( - f'{ELEVENLABS_API_BASE_URL}/v1/voices', - headers={ - 'xi-api-key': api_key, - 'Content-Type': 'application/json', - }, - timeout=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST, - ) - response.raise_for_status() - voices_data = response.json() + timeout = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST) + async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: + async with session.get( + f'{ELEVENLABS_API_BASE_URL}/v1/voices', + headers={ + 'xi-api-key': api_key, + 'Content-Type': 'application/json', + }, + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as response: + response.raise_for_status() + voices_data = await response.json() - voices = {} - for voice in voices_data.get('voices', []): - voices[voice['voice_id']] = voice['name'] - except requests.RequestException as e: - # Avoid @lru_cache with exception + voices = {} + for voice in voices_data.get('voices', []): + voices[voice['voice_id']] = voice['name'] + except Exception as e: log.error(f'Error fetching voices: {str(e)}') raise RuntimeError(f'Error fetching voices: {str(e)}') @@ -1454,4 +1478,4 @@ def get_elevenlabs_voices(api_key: str) -> dict: @router.get('/voices') async def get_voices(request: Request, user=Depends(get_verified_user)): - return {'voices': [{'id': k, 'name': v} for k, v in get_available_voices(request).items()]} + return {'voices': [{'id': k, 'name': v} for k, v in (await get_available_voices(request)).items()]} diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index 651e123b64..2a6f0f6dcd 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -810,7 +810,7 @@ async def signout(request: Request, response: Response, db: AsyncSession = Depen oauth_id_token = session.token.get('id_token') try: async with ClientSession(trust_env=True) as session: - async with session.get(oauth_server_metadata_url) as r: + async with session.get(oauth_server_metadata_url, ssl=AIOHTTP_CLIENT_SESSION_SSL) as r: if r.status == 200: openid_data = await r.json() logout_url = openid_data.get('end_session_endpoint') @@ -971,7 +971,9 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)): 'FOLDER_MAX_FILE_COUNT': request.app.state.config.FOLDER_MAX_FILE_COUNT, 'AUTOMATION_MAX_COUNT': request.app.state.config.AUTOMATION_MAX_COUNT, 'AUTOMATION_MIN_INTERVAL': request.app.state.config.AUTOMATION_MIN_INTERVAL, + 'ENABLE_AUTOMATIONS': request.app.state.config.ENABLE_AUTOMATIONS, 'ENABLE_CHANNELS': request.app.state.config.ENABLE_CHANNELS, + 'ENABLE_CALENDAR': request.app.state.config.ENABLE_CALENDAR, 'ENABLE_MEMORIES': request.app.state.config.ENABLE_MEMORIES, 'ENABLE_NOTES': request.app.state.config.ENABLE_NOTES, 'ENABLE_USER_WEBHOOKS': request.app.state.config.ENABLE_USER_WEBHOOKS, @@ -999,7 +1001,9 @@ class AdminConfig(BaseModel): FOLDER_MAX_FILE_COUNT: Optional[int | str] = None AUTOMATION_MAX_COUNT: Optional[int | str] = None AUTOMATION_MIN_INTERVAL: Optional[int | str] = None + ENABLE_AUTOMATIONS: bool ENABLE_CHANNELS: bool + ENABLE_CALENDAR: bool ENABLE_MEMORIES: bool ENABLE_NOTES: bool ENABLE_USER_WEBHOOKS: bool @@ -1030,7 +1034,9 @@ async def update_admin_config(request: Request, form_data: AdminConfig, user=Dep request.app.state.config.AUTOMATION_MIN_INTERVAL = ( int(form_data.AUTOMATION_MIN_INTERVAL) if form_data.AUTOMATION_MIN_INTERVAL else '' ) + request.app.state.config.ENABLE_AUTOMATIONS = form_data.ENABLE_AUTOMATIONS request.app.state.config.ENABLE_CHANNELS = form_data.ENABLE_CHANNELS + request.app.state.config.ENABLE_CALENDAR = form_data.ENABLE_CALENDAR request.app.state.config.ENABLE_MEMORIES = form_data.ENABLE_MEMORIES request.app.state.config.ENABLE_NOTES = form_data.ENABLE_NOTES @@ -1073,7 +1079,9 @@ async def update_admin_config(request: Request, form_data: AdminConfig, user=Dep 'FOLDER_MAX_FILE_COUNT': request.app.state.config.FOLDER_MAX_FILE_COUNT, 'AUTOMATION_MAX_COUNT': request.app.state.config.AUTOMATION_MAX_COUNT, 'AUTOMATION_MIN_INTERVAL': request.app.state.config.AUTOMATION_MIN_INTERVAL, + 'ENABLE_AUTOMATIONS': request.app.state.config.ENABLE_AUTOMATIONS, 'ENABLE_CHANNELS': request.app.state.config.ENABLE_CHANNELS, + 'ENABLE_CALENDAR': request.app.state.config.ENABLE_CALENDAR, 'ENABLE_MEMORIES': request.app.state.config.ENABLE_MEMORIES, 'ENABLE_NOTES': request.app.state.config.ENABLE_NOTES, 'ENABLE_USER_WEBHOOKS': request.app.state.config.ENABLE_USER_WEBHOOKS, diff --git a/backend/open_webui/routers/automations.py b/backend/open_webui/routers/automations.py index d68bd8e2c6..4ff66feb97 100644 --- a/backend/open_webui/routers/automations.py +++ b/backend/open_webui/routers/automations.py @@ -39,6 +39,11 @@ PAGE_ITEM_COUNT = 30 async def check_automations_permission(request, user): + if not request.app.state.config.ENABLE_AUTOMATIONS: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) if user.role != 'admin' and not await has_permission( user.id, 'features.automations', request.app.state.config.USER_PERMISSIONS ): @@ -158,7 +163,7 @@ async def create_new_automation( ): await check_automations_permission(request, user) try: - validate_rrule(form_data.data.rrule) + validate_rrule(form_data.data.rrule, tz=user.timezone) except ValueError as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -208,7 +213,7 @@ async def update_automation_by_id( check_automation_access(automation, user) try: - validate_rrule(form_data.data.rrule) + validate_rrule(form_data.data.rrule, tz=user.timezone) except ValueError as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/backend/open_webui/routers/calendar.py b/backend/open_webui/routers/calendar.py new file mode 100644 index 0000000000..c95888ebfa --- /dev/null +++ b/backend/open_webui/routers/calendar.py @@ -0,0 +1,389 @@ +import logging +import time +from typing import Optional + +from fastapi import APIRouter, Depends, HTTPException, Request, status + +from open_webui.models.calendar import ( + Calendars, + CalendarEvents, + CalendarEventAttendees, + CalendarForm, + CalendarUpdateForm, + CalendarEventForm, + CalendarEventUpdateForm, + CalendarModel, + CalendarEventModel, + CalendarEventUserResponse, + CalendarEventListResponse, + RSVPForm, +) +from open_webui.models.access_grants import AccessGrants +from open_webui.models.groups import Groups +from open_webui.models.users import UserModel +from open_webui.utils.auth import get_verified_user +from open_webui.utils.access_control import has_permission +from open_webui.utils.calendar import expand_recurring_event +from open_webui.constants import ERROR_MESSAGES + +log = logging.getLogger(__name__) + +router = APIRouter() + +SCHEDULED_TASKS_CALENDAR_ID = '__scheduled_tasks__' + + +async def check_calendar_permission(request: Request, user): + """Check global feature flag AND per-user permission for calendar access.""" + if not request.app.state.config.ENABLE_CALENDAR: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + if user.role != 'admin' and not await has_permission( + user.id, 'features.calendar', request.app.state.config.USER_PERMISSIONS + ): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + + +async def _user_has_automations(request: Request, user) -> bool: + """Check if automations feature is available to this user.""" + if not getattr(request.app.state.config, 'ENABLE_AUTOMATIONS', False): + return False + if user.role == 'admin': + return True + return await has_permission(user.id, 'features.automations', request.app.state.config.USER_PERMISSIONS) + + +async def _check_calendar_access(calendar_id: str, user: UserModel, permission: str = 'write') -> CalendarModel: + """Verify user has access to a calendar. Returns the calendar or raises 403/404.""" + cal = await Calendars.get_calendar_by_id(calendar_id) + if not cal: + raise HTTPException(status_code=404, detail='Calendar not found') + if cal.user_id == user.id or user.role == 'admin': + return cal + user_groups = await Groups.get_groups_by_member_id(user.id) + user_group_ids = [g.id for g in user_groups] + if await AccessGrants.has_access( + user_id=user.id, + resource_type='calendar', + resource_id=cal.id, + permission=permission, + user_group_ids=user_group_ids, + ): + return cal + raise HTTPException(status_code=403, detail='Access denied') + + +#################### +# Calendar CRUD (static paths first) +#################### + + +@router.get('/', response_model=list[CalendarModel]) +async def get_calendars(request: Request, user: UserModel = Depends(get_verified_user)): + """List user's calendars (owned + shared), plus a virtual Scheduled Tasks calendar + when automations are available.""" + await check_calendar_permission(request, user) + calendars = await Calendars.get_calendars_by_user(user.id) + + if await _user_has_automations(request, user): + now = int(time.time_ns()) + calendars.append( + CalendarModel( + id=SCHEDULED_TASKS_CALENDAR_ID, + user_id=user.id, + name='Scheduled Tasks', + color='#8b5cf6', + is_default=False, + is_system=True, + created_at=now, + updated_at=now, + ) + ) + + return calendars + + +@router.post('/create', response_model=CalendarModel) +async def create_calendar(request: Request, form_data: CalendarForm, user: UserModel = Depends(get_verified_user)): + """Create a new user calendar.""" + await check_calendar_permission(request, user) + return await Calendars.insert_new_calendar(user.id, form_data) + + +#################### +# Event CRUD (before /{calendar_id} to avoid route conflicts) +#################### + + +@router.get('/events') +async def get_events( + request: Request, + start: str, + end: str, + calendar_ids: Optional[str] = None, + user: UserModel = Depends(get_verified_user), +): + """Get events in date range. + + Args: + start: ISO 8601 datetime string (e.g. 2026-04-01T00:00:00) + end: ISO 8601 datetime string (e.g. 2026-05-01T00:00:00) + calendar_ids: optional comma-separated list to filter + + Includes: + - Stored events from the database + - Virtual events computed from active automation RRULEs (Scheduled Tasks calendar) + """ + await check_calendar_permission(request, user) + from datetime import datetime + + try: + start_dt = datetime.fromisoformat(start.replace('Z', '+00:00')) + end_dt = datetime.fromisoformat(end.replace('Z', '+00:00')) + except ValueError: + raise HTTPException(status_code=400, detail='Invalid date format. Use ISO 8601 (e.g. 2026-04-01T00:00:00)') + + NS = 1_000_000 + start_ns = int(start_dt.timestamp() * 1000) * NS + end_ns = int(end_dt.timestamp() * 1000) * NS + cal_id_list = calendar_ids.split(',') if calendar_ids else None + + # 1. Stored events + events = await CalendarEvents.get_events_by_range( + user_id=user.id, + start=start_ns, + end=end_ns, + calendar_ids=cal_id_list, + ) + + # Expand recurring stored events + expanded = [] + for event in events: + event_dict = event.model_dump() + if event_dict.get('rrule'): + instances = expand_recurring_event(event_dict, start_ns, end_ns, tz=user.timezone) + for inst in instances: + expanded.append(CalendarEventUserResponse(**{**inst, 'user': event.user})) + else: + expanded.append(event) + + # 2. Virtual automation events (Scheduled Tasks calendar) + if await _user_has_automations(request, user) and ( + cal_id_list is None or SCHEDULED_TASKS_CALENDAR_ID in cal_id_list + ): + try: + from open_webui.models.automations import Automations, AutomationRuns + + # Future runs: expand RRULEs for active automations only + active_automations = await Automations.get_active_by_user(user.id) + for auto in active_automations: + rrule_str = auto.data.get('rrule', '') if auto.data else '' + if not rrule_str: + continue + + virtual = { + 'id': f'auto_{auto.id}', + 'calendar_id': SCHEDULED_TASKS_CALENDAR_ID, + 'user_id': user.id, + 'title': auto.name, + 'description': auto.data.get('prompt', '') if auto.data else '', + 'start_at': auto.next_run_at or 0, + 'end_at': None, + 'all_day': False, + 'rrule': rrule_str, + 'color': None, + 'location': None, + 'data': None, + 'meta': {'automation_id': auto.id}, + 'is_cancelled': False, + 'attendees': [], + 'created_at': auto.created_at, + 'updated_at': auto.updated_at, + 'user': None, + } + + # Only expand into the future — past runs are handled below + now_ns = int(time.time_ns()) + rrule_start = max(start_ns, now_ns) + instances = expand_recurring_event(virtual, rrule_start, end_ns, tz=user.timezone) + for inst in instances: + expanded.append(CalendarEventUserResponse(**inst)) + + # Past runs: single range query joined with automation + runs_with_auto = await AutomationRuns.get_runs_by_user_range(user.id, start_ns, end_ns) + for run, auto in runs_with_auto: + expanded.append( + CalendarEventUserResponse( + id=f'run_{run.id}', + calendar_id=SCHEDULED_TASKS_CALENDAR_ID, + user_id=user.id, + title=auto.name, + description=run.error if run.status == 'error' else '', + start_at=run.created_at, + end_at=None, + all_day=False, + color=None, + location=None, + data=None, + meta={ + 'automation_id': auto.id, + 'run_id': run.id, + 'chat_id': run.chat_id, + 'status': run.status, + }, + is_cancelled=False, + attendees=[], + created_at=run.created_at, + updated_at=run.created_at, + user=None, + ) + ) + except Exception as e: + log.warning(f'Failed to compute automation events: {e}', exc_info=True) + + return [e.model_dump() if hasattr(e, 'model_dump') else e for e in expanded] + + +@router.post('/events/create', response_model=CalendarEventModel) +async def create_event(request: Request, form_data: CalendarEventForm, user: UserModel = Depends(get_verified_user)): + await check_calendar_permission(request, user) + await _check_calendar_access(form_data.calendar_id, user, 'write') + return await CalendarEvents.insert_new_event(user.id, form_data) + + +@router.get('/events/search', response_model=CalendarEventListResponse) +async def search_events( + request: Request, + query: Optional[str] = None, + skip: int = 0, + limit: int = 30, + user: UserModel = Depends(get_verified_user), +): + await check_calendar_permission(request, user) + return await CalendarEvents.search_events(user_id=user.id, query=query, skip=skip, limit=limit) + + +@router.get('/events/{event_id}', response_model=CalendarEventModel) +async def get_event(request: Request, event_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_permission(request, user) + event = await CalendarEvents.get_event_by_id(event_id) + if not event: + raise HTTPException(status_code=404, detail='Event not found') + + await _check_calendar_access(event.calendar_id, user, 'read') + + return event + + +@router.post('/events/{event_id}/update', response_model=CalendarEventModel) +async def update_event( + request: Request, event_id: str, form_data: CalendarEventUpdateForm, user: UserModel = Depends(get_verified_user) +): + await check_calendar_permission(request, user) + event = await CalendarEvents.get_event_by_id(event_id) + if not event: + raise HTTPException(status_code=404, detail='Event not found') + + await _check_calendar_access(event.calendar_id, user, 'write') + + updated = await CalendarEvents.update_event_by_id(event_id, form_data) + if not updated: + raise HTTPException(status_code=500, detail='Failed to update') + return updated + + +@router.delete('/events/{event_id}/delete') +async def delete_event(request: Request, event_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_permission(request, user) + event = await CalendarEvents.get_event_by_id(event_id) + if not event: + raise HTTPException(status_code=404, detail='Event not found') + + await _check_calendar_access(event.calendar_id, user, 'write') + + result = await CalendarEvents.delete_event_by_id(event_id) + if not result: + raise HTTPException(status_code=500, detail='Failed to delete') + return {'status': True} + + +@router.post('/events/{event_id}/rsvp', response_model=dict) +async def rsvp_event( + request: Request, event_id: str, form_data: RSVPForm, user: UserModel = Depends(get_verified_user) +): + """Update own RSVP status for an event.""" + await check_calendar_permission(request, user) + if form_data.status not in ('accepted', 'declined', 'tentative', 'pending'): + raise HTTPException(status_code=400, detail='Invalid status') + + result = await CalendarEventAttendees.update_rsvp(event_id, user.id, form_data.status) + if not result: + raise HTTPException(status_code=404, detail='Not an attendee of this event') + return {'status': True, 'rsvp': result.status} + + +#################### +# Calendar by ID (dynamic path — MUST come after /events* routes) +#################### + + +@router.get('/{calendar_id}', response_model=CalendarModel) +async def get_calendar_by_id(request: Request, calendar_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_permission(request, user) + cal = await _check_calendar_access(calendar_id, user, 'read') + return cal + + +@router.post('/{calendar_id}/update', response_model=CalendarModel) +async def update_calendar( + request: Request, calendar_id: str, form_data: CalendarUpdateForm, user: UserModel = Depends(get_verified_user) +): + await check_calendar_permission(request, user) + cal = await _check_calendar_access(calendar_id, user, 'write') + + # Only owner/admin can change access grants + if form_data.access_grants is not None and cal.user_id != user.id and user.role != 'admin': + raise HTTPException(status_code=403, detail='Only owner can manage sharing') + + updated = await Calendars.update_calendar_by_id(calendar_id, form_data) + if not updated: + raise HTTPException(status_code=500, detail='Failed to update') + return updated + + +@router.delete('/{calendar_id}/delete') +async def delete_calendar(request: Request, calendar_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_permission(request, user) + + # Block deletion of the virtual Scheduled Tasks calendar + if calendar_id == SCHEDULED_TASKS_CALENDAR_ID: + raise HTTPException(status_code=400, detail='System calendars cannot be deleted') + + cal = await _check_calendar_access(calendar_id, user, 'write') + + # Only owner/admin can delete + if cal.user_id != user.id and user.role != 'admin': + raise HTTPException(status_code=403, detail='Only owner can delete calendar') + + # Block deletion of default calendar + if cal.is_default: + raise HTTPException(status_code=400, detail='Default calendar cannot be deleted') + + result = await Calendars.delete_calendar_by_id(calendar_id) + if not result: + raise HTTPException(status_code=500, detail='Failed to delete') + return {'status': True} + + +@router.post('/{calendar_id}/default') +async def set_default_calendar(request: Request, calendar_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_permission(request, user) + cal = await Calendars.set_default_calendar(user.id, calendar_id) + if not cal: + raise HTTPException(status_code=404, detail='Calendar not found') + return cal diff --git a/backend/open_webui/routers/channels.py b/backend/open_webui/routers/channels.py index a771b95920..487899fccf 100644 --- a/backend/open_webui/routers/channels.py +++ b/backend/open_webui/routers/channels.py @@ -305,7 +305,7 @@ async def create_new_channel( detail=ERROR_MESSAGES.UNAUTHORIZED, ) - form_data.access_grants = filter_allowed_access_grants( + form_data.access_grants = await filter_allowed_access_grants( request.app.state.config.USER_PERMISSIONS, user.id, user.role, @@ -643,7 +643,7 @@ async def update_channel_by_id( if channel.user_id != user.id and user.role != 'admin': raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()) - form_data.access_grants = filter_allowed_access_grants( + form_data.access_grants = await filter_allowed_access_grants( request.app.state.config.USER_PERMISSIONS, user.id, user.role, @@ -923,15 +923,13 @@ async def model_response_handler(request, channel, message, user, db=None): thread_history = [] images = [] - message_users = {} + + # Batch fetch all users in a single query (fixes N+1 problem) + user_ids = list({message.user_id for message in thread_messages}) + message_users = {user.id: user for user in await Users.get_users_by_user_ids(user_ids, db=db)} for thread_message in thread_messages: - message_user = None - if thread_message.user_id not in message_users: - message_user = await Users.get_user_by_id(thread_message.user_id, db=db) - message_users[thread_message.user_id] = message_user - else: - message_user = message_users[thread_message.user_id] + message_user = message_users.get(thread_message.user_id) if thread_message.meta and thread_message.meta.get('model_id', None): # If the message was sent by a model, use the model name diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 1980d22362..7cf125f7c7 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -17,13 +17,14 @@ from open_webui.models.chats import ( ChatResponse, Chats, ChatTitleIdResponse, - SharedChatResponse, ChatStatsExport, AggregateChatStats, ChatBody, ChatHistoryStats, MessageStats, ) +from open_webui.models.shared_chats import SharedChats, SharedChatResponse +from open_webui.models.access_grants import AccessGrants from open_webui.models.tags import TagModel, Tags from open_webui.models.folders import Folders from open_webui.internal.db import get_async_session @@ -35,7 +36,7 @@ from pydantic import BaseModel from open_webui.utils.auth import get_admin_user, get_verified_user -from open_webui.utils.access_control import has_permission +from open_webui.utils.access_control import has_permission, filter_allowed_access_grants log = logging.getLogger(__name__) @@ -807,7 +808,7 @@ async def get_shared_session_user_chat_list( if direction: filter['direction'] = direction - return await Chats.get_shared_chat_list_by_user_id( + return await SharedChats.get_by_user_id( user.id, filter=filter, skip=skip, @@ -828,17 +829,32 @@ async def get_shared_chat_by_id( if user.role == 'pending': raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND) - if user.role == 'user' or (user.role == 'admin' and not ENABLE_ADMIN_CHAT_ACCESS): - chat = await Chats.get_chat_by_share_id(share_id, db=db) - elif user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS: + if user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS: chat = await Chats.get_chat_by_id(share_id, db=db) - - if chat: - return ChatResponse(**chat.model_dump()) - else: + chat = await Chats.get_chat_by_share_id(share_id, db=db) + + if not chat: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND) + # Look up the original chat_id to check access grants + shared = await SharedChats.get_by_id(share_id, db=db) + if shared: + has_grant = await AccessGrants.has_access( + user_id=user.id, + resource_type='shared_chat', + resource_id=shared.chat_id, + permission='read', + db=db, + ) + if not has_grant: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + + return ChatResponse(**chat.model_dump()) + ############################ # GetChatsByTags @@ -878,11 +894,25 @@ async def get_user_chat_list_by_tag_name( async def get_chat_by_id(id: str, user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session)): chat = await Chats.get_chat_by_id_and_user_id(id, user.id, db=db) + if not chat: + # Check if user has access via access grants (shared_chat grants) + if user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS: + chat = await Chats.get_chat_by_id(id, db=db) + else: + has_grant = await AccessGrants.has_access( + user_id=user.id, + resource_type='shared_chat', + resource_id=id, + permission='read', + db=db, + ) + if has_grant: + chat = await Chats.get_chat_by_id(id, db=db) + if chat: return ChatResponse(**chat.model_dump()) - else: - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND) + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND) ############################ @@ -948,7 +978,7 @@ async def update_chat_message_by_id( event_emitter = await get_event_emitter( { - 'user_id': user.id, + 'user_id': chat.user_id, 'chat_id': id, 'message_id': message_id, }, @@ -1002,7 +1032,7 @@ async def send_chat_message_event_by_id( event_emitter = await get_event_emitter( { - 'user_id': user.id, + 'user_id': chat.user_id, 'chat_id': id, 'message_id': message_id, } @@ -1158,39 +1188,58 @@ async def clone_shared_chat_by_id( else: chat = await Chats.get_chat_by_share_id(id, db=db) - if chat: - updated_chat = { - **chat.chat, - 'originalChatId': chat.id, - 'branchPointMessageId': chat.chat['history']['currentId'], - 'title': f'Clone of {chat.title}', - } - - chats = await Chats.import_chats( - user.id, - [ - ChatImportForm( - **{ - 'chat': updated_chat, - 'meta': chat.meta, - 'pinned': chat.pinned, - 'folder_id': chat.folder_id, - } - ) - ], - db=db, + if not chat: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.NOT_FOUND, ) - if chats: - chat = chats[0] - return ChatResponse(**chat.model_dump()) - else: + # Enforce access grants + shared = await SharedChats.get_by_id(id, db=db) + if shared and user.role != 'admin': + has_grant = await AccessGrants.has_access( + user_id=user.id, + resource_type='shared_chat', + resource_id=shared.chat_id, + permission='read', + db=db, + ) + if not has_grant: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=ERROR_MESSAGES.DEFAULT(), + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) + + updated_chat = { + **chat.chat, + 'originalChatId': chat.id, + 'branchPointMessageId': chat.chat['history']['currentId'], + 'title': f'Clone of {chat.title}', + } + + chats = await Chats.import_chats( + user.id, + [ + ChatImportForm( + **{ + 'chat': updated_chat, + 'meta': chat.meta, + 'pinned': chat.pinned, + 'folder_id': chat.folder_id, + } + ) + ], + db=db, + ) + + if chats: + chat = chats[0] + return ChatResponse(**chat.model_dump()) else: - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.DEFAULT()) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=ERROR_MESSAGES.DEFAULT(), + ) ############################ @@ -1241,16 +1290,28 @@ async def share_chat_by_id( if chat: if chat.share_id: - shared_chat = await Chats.update_shared_chat_by_chat_id(chat.id, db=db) - return ChatResponse(**shared_chat.model_dump()) + # Re-snapshot existing share + shared = await SharedChats.update(chat.share_id, db=db) + if shared: + # Re-fetch the original chat to return + chat = await Chats.get_chat_by_id(id, db=db) + return ChatResponse(**chat.model_dump()) - shared_chat = await Chats.insert_shared_chat_by_chat_id(chat.id, db=db) - if not shared_chat: + # Create new share + shared = await SharedChats.create(id, user.id, db=db) + if not shared: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=ERROR_MESSAGES.DEFAULT(), ) - return ChatResponse(**shared_chat.model_dump()) + # Set share_id on the original chat + chat = await Chats.update_chat_share_id_by_id(id, shared.id, db=db) + if not chat: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=ERROR_MESSAGES.DEFAULT(), + ) + return ChatResponse(**chat.model_dump()) else: raise HTTPException( @@ -1260,7 +1321,7 @@ async def share_chat_by_id( ############################ -# DeletedSharedChatById +# DeleteSharedChatById ############################ @@ -1273,10 +1334,13 @@ async def delete_shared_chat_by_id( if not chat.share_id: return False - result = await Chats.delete_shared_chat_by_chat_id(id, db=db) - update_result = await Chats.update_chat_share_id_by_id(id, None, db=db) + await SharedChats.delete_by_chat_id(id, db=db) + await Chats.update_chat_share_id_by_id(id, None, db=db) - return result and update_result != None + # Revoke all access grants for this shared chat + await AccessGrants.set_access_grants('shared_chat', id, [], db=db) + + return True else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -1284,6 +1348,85 @@ async def delete_shared_chat_by_id( ) +############################ +# UpdateSharedChatAccessById +############################ + + +class ChatAccessGrantsForm(BaseModel): + access_grants: list[dict] + + +@router.post('/shared/{id}/access/update', response_model=Optional[ChatResponse]) +async def update_shared_chat_access_by_id( + request: Request, + id: str, + form_data: ChatAccessGrantsForm, + user=Depends(get_verified_user), + db: AsyncSession = Depends(get_async_session), +): + chat = await Chats.get_chat_by_id_and_user_id(id, user.id, db=db) + if not chat: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=ERROR_MESSAGES.NOT_FOUND, + ) + + if chat.user_id != user.id and user.role != 'admin': + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + + form_data.access_grants = await filter_allowed_access_grants( + request.app.state.config.USER_PERMISSIONS, + user.id, + user.role, + form_data.access_grants, + 'sharing.public_chats', + ) + + await AccessGrants.set_access_grants('shared_chat', id, form_data.access_grants, db=db) + + return ChatResponse(**chat.model_dump()) + + +############################ +# GetSharedChatAccessById +############################ + + +@router.get('/shared/{id}/access', response_model=list) +async def get_shared_chat_access_by_id( + id: str, + user=Depends(get_verified_user), + db: AsyncSession = Depends(get_async_session), +): + chat = await Chats.get_chat_by_id_and_user_id(id, user.id, db=db) + if not chat: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=ERROR_MESSAGES.NOT_FOUND, + ) + + if chat.user_id != user.id and user.role != 'admin': + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + + grants = await AccessGrants.get_grants_by_resource('shared_chat', id, db=db) + return [ + { + 'id': g.id, + 'principal_type': g.principal_type, + 'principal_id': g.principal_id, + 'permission': g.permission, + } + for g in grants + ] + + ############################ # UpdateChatFolderIdById ############################ diff --git a/backend/open_webui/routers/configs.py b/backend/open_webui/routers/configs.py index 7c54c09039..02b16d8e5b 100644 --- a/backend/open_webui/routers/configs.py +++ b/backend/open_webui/routers/configs.py @@ -6,7 +6,7 @@ import aiohttp from typing import Optional -from open_webui.env import AIOHTTP_CLIENT_TIMEOUT +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.config import get_config, save_config, async_save_config from open_webui.config import BannerModel @@ -293,7 +293,9 @@ async def verify_terminal_server_connection( ) as session: # Orchestrators expose a policies API; plain terminals don't. try: - async with session.get(f'{base_url}/api/v1/policies', headers=headers) as resp: + async with session.get( + f'{base_url}/api/v1/policies', headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.ok: return {'status': True, 'type': 'orchestrator'} except Exception: @@ -301,7 +303,9 @@ async def verify_terminal_server_connection( # Fall back to open-terminal config endpoint. try: - async with session.get(f'{base_url}/api/config', headers=headers) as resp: + async with session.get( + f'{base_url}/api/config', headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.ok: return {'status': True, 'type': 'terminal'} except Exception: @@ -342,7 +346,9 @@ async def put_terminal_server_policy( timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT), ) as session: policy_url = f'{base_url}/api/v1/policies/{form_data.policy_id}' - async with session.put(policy_url, headers=headers, json=form_data.policy_data) as resp: + async with session.put( + policy_url, headers=headers, json=form_data.policy_data, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.ok: return await resp.json() detail = await resp.text() @@ -369,7 +375,9 @@ async def verify_tool_servers_config(request: Request, form_data: ToolServerConn trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT), ) as session: - async with session.get(discovery_url) as oauth_server_metadata_response: + async with session.get( + discovery_url, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as oauth_server_metadata_response: if oauth_server_metadata_response.status == 200: try: oauth_server_metadata = OAuthMetadata.model_validate( diff --git a/backend/open_webui/routers/functions.py b/backend/open_webui/routers/functions.py index 1d0f0342d2..f40cd1ab82 100644 --- a/backend/open_webui/routers/functions.py +++ b/backend/open_webui/routers/functions.py @@ -6,7 +6,7 @@ import aiohttp from pathlib import Path from typing import Optional -from open_webui.env import AIOHTTP_CLIENT_TIMEOUT +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT from open_webui.models.functions import ( FunctionForm, FunctionModel, @@ -117,7 +117,9 @@ async def load_function_from_url(request: Request, form_data: LoadUrlForm, user= async with aiohttp.ClientSession( trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) ) as session: - async with session.get(url, headers={'Content-Type': 'application/json'}) as resp: + async with session.get( + url, headers={'Content-Type': 'application/json'}, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.status != 200: raise HTTPException(status_code=resp.status, detail='Failed to fetch the function') data = await resp.text() diff --git a/backend/open_webui/routers/images.py b/backend/open_webui/routers/images.py index 37dda2eb1b..7ef4938b2e 100644 --- a/backend/open_webui/routers/images.py +++ b/backend/open_webui/routers/images.py @@ -11,7 +11,7 @@ from typing import Optional from urllib.parse import quote import aiohttp -import requests + from fastapi import APIRouter, Depends, HTTPException, Request, UploadFile from fastapi.responses import FileResponse @@ -52,32 +52,36 @@ IMAGE_CACHE_DIR.mkdir(parents=True, exist_ok=True) router = APIRouter() -def set_image_model(request: Request, model: str): +async def set_image_model(request: Request, model: str): log.info(f'Setting image model to {model}') request.app.state.config.IMAGE_GENERATION_MODEL = model if request.app.state.config.IMAGE_GENERATION_ENGINE in ['', 'automatic1111']: api_auth = get_automatic1111_api_auth(request) try: - r = requests.get( + session = await get_session() + async with session.get( url=f'{request.app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options', headers={'authorization': api_auth}, - ) - options = r.json() + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as r: + options = await r.json() if model != options['sd_model_checkpoint']: options['sd_model_checkpoint'] = model - r = requests.post( + async with session.post( url=f'{request.app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options', json=options, headers={'authorization': api_auth}, - ) + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as r: + r.raise_for_status() except Exception as e: log.debug(f'{e}') return request.app.state.config.IMAGE_GENERATION_MODEL -def get_image_model(request): +async def get_image_model(request): if request.app.state.config.IMAGE_GENERATION_ENGINE == 'openai': return ( request.app.state.config.IMAGE_GENERATION_MODEL @@ -99,14 +103,15 @@ def get_image_model(request): or request.app.state.config.IMAGE_GENERATION_ENGINE == '' ): try: - r = requests.get( + session = await get_session() + async with session.get( url=f'{request.app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options', headers={'authorization': get_automatic1111_api_auth(request)}, - ) - options = r.json() + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as r: + options = await r.json() return options['sd_model_checkpoint'] except Exception as e: - request.app.state.config.ENABLE_IMAGE_GENERATION = False raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e)) @@ -200,7 +205,7 @@ async def update_config(request: Request, form_data: ImagesConfig, user=Depends( request.app.state.config.ENABLE_IMAGE_PROMPT_GENERATION = form_data.ENABLE_IMAGE_PROMPT_GENERATION request.app.state.config.IMAGE_GENERATION_ENGINE = form_data.IMAGE_GENERATION_ENGINE - set_image_model(request, form_data.IMAGE_GENERATION_MODEL) + await set_image_model(request, form_data.IMAGE_GENERATION_MODEL) if form_data.IMAGE_SIZE == 'auto' and not re.match( IMAGE_AUTO_SIZE_MODELS_REGEX_PATTERN, form_data.IMAGE_GENERATION_MODEL ): @@ -324,7 +329,6 @@ async def verify_url(request: Request, user=Depends(get_admin_user)): r.raise_for_status() return True except Exception: - request.app.state.config.ENABLE_IMAGE_GENERATION = False raise HTTPException(status_code=400, detail=ERROR_MESSAGES.INVALID_URL) elif request.app.state.config.IMAGE_GENERATION_ENGINE == 'comfyui': headers = None @@ -340,7 +344,6 @@ async def verify_url(request: Request, user=Depends(get_admin_user)): r.raise_for_status() return True except Exception: - request.app.state.config.ENABLE_IMAGE_GENERATION = False raise HTTPException(status_code=400, detail=ERROR_MESSAGES.INVALID_URL) else: return True @@ -421,7 +424,6 @@ async def get_models(request: Request, user=Depends(get_verified_user)): ) ) except Exception as e: - request.app.state.config.ENABLE_IMAGE_GENERATION = False raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e)) @@ -437,21 +439,22 @@ class CreateImageForm(BaseModel): GenerateImageForm = CreateImageForm # Alias for backward compatibility -def get_image_data(data: str, headers=None): +async def get_image_data(data: str, headers=None): try: if data.startswith('http://') or data.startswith('https://'): - if headers: - r = requests.get(data, headers=headers) - else: - r = requests.get(data) - - r.raise_for_status() - if r.headers['content-type'].split('/')[0] == 'image': - mime_type = r.headers['content-type'] - return r.content, mime_type - else: - log.error('Url does not point to an image.') - return None + session = await get_session() + async with session.get( + data, + headers=headers, + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as r: + r.raise_for_status() + content_type = r.headers.get('content-type', '') + if content_type.split('/')[0] == 'image': + return await r.read(), content_type + else: + log.error('Url does not point to an image.') + return None, None else: if ',' in data: header, encoded = data.split(',', 1) @@ -541,7 +544,7 @@ async def image_generations( metadata = metadata or {} - model = get_image_model(request) + model = await get_image_model(request) try: if request.app.state.config.IMAGE_GENERATION_ENGINE == 'openai': @@ -595,12 +598,12 @@ async def image_generations( for image in res['data']: if image_url := image.get('url', None): - image_data, content_type = get_image_data( + image_data, content_type = await get_image_data( image_url, {k: v for k, v in headers.items() if k != 'Content-Type'}, ) else: - image_data, content_type = get_image_data(image['b64_json']) + image_data, content_type = await get_image_data(image['b64_json']) _, url = await upload_image(request, image_data, content_type, {**data, **metadata}, user) images.append({'url': url}) @@ -645,14 +648,14 @@ async def image_generations( if model.endswith(':predict'): for image in res['predictions']: - image_data, content_type = get_image_data(image['bytesBase64Encoded']) + image_data, content_type = await get_image_data(image['bytesBase64Encoded']) _, url = await upload_image(request, image_data, content_type, {**data, **metadata}, user) images.append({'url': url}) elif model.endswith(':generateContent'): for image in res['candidates']: for part in image['content']['parts']: if part.get('inlineData', {}).get('data'): - image_data, content_type = get_image_data(part['inlineData']['data']) + image_data, content_type = await get_image_data(part['inlineData']['data']) _, url = await upload_image( request, image_data, @@ -705,7 +708,7 @@ async def image_generations( if request.app.state.config.COMFYUI_API_KEY: headers = {'Authorization': f'Bearer {request.app.state.config.COMFYUI_API_KEY}'} - image_data, content_type = get_image_data(image['url'], headers) + image_data, content_type = await get_image_data(image['url'], headers) _, url = await upload_image( request, image_data, @@ -720,7 +723,7 @@ async def image_generations( or request.app.state.config.IMAGE_GENERATION_ENGINE == '' ): if form_data.model: - set_image_model(request, form_data.model) + await set_image_model(request, form_data.model) data = { 'prompt': form_data.prompt, @@ -751,7 +754,7 @@ async def image_generations( images = [] for image in res['images']: - image_data, content_type = get_image_data(image) + image_data, content_type = await get_image_data(image) _, url = await upload_image( request, image_data, @@ -919,12 +922,12 @@ async def image_edits( images = [] for image in res['data']: if image_url := image.get('url', None): - image_data, content_type = get_image_data( + image_data, content_type = await get_image_data( image_url, {k: v for k, v in headers.items() if k != 'Content-Type'}, ) else: - image_data, content_type = get_image_data(image['b64_json']) + image_data, content_type = await get_image_data(image['b64_json']) _, url = await upload_image(request, image_data, content_type, {**data, **metadata}, user) images.append({'url': url}) @@ -975,7 +978,7 @@ async def image_edits( for image in res['candidates']: for part in image['content']['parts']: if part.get('inlineData', {}).get('data'): - image_data, content_type = get_image_data(part['inlineData']['data']) + image_data, content_type = await get_image_data(part['inlineData']['data']) _, url = await upload_image( request, image_data, @@ -1055,7 +1058,7 @@ async def image_edits( if request.app.state.config.IMAGES_EDIT_COMFYUI_API_KEY: headers = {'Authorization': f'Bearer {request.app.state.config.IMAGES_EDIT_COMFYUI_API_KEY}'} - image_data, content_type = get_image_data(image_url, headers) + image_data, content_type = await get_image_data(image_url, headers) _, url = await upload_image( request, image_data, diff --git a/backend/open_webui/routers/knowledge.py b/backend/open_webui/routers/knowledge.py index 77b72cacf0..f503169fc0 100644 --- a/backend/open_webui/routers/knowledge.py +++ b/backend/open_webui/routers/knowledge.py @@ -539,10 +539,10 @@ async def update_knowledge_access_by_id( 'sharing.public_knowledge', ) - await AccessGrants.set_access_grants('knowledge', id, form_data.access_grants, db=db) + knowledge.access_grants = await AccessGrants.set_access_grants('knowledge', id, form_data.access_grants, db=db) return KnowledgeFilesResponse( - **(await Knowledges.get_knowledge_by_id(id=id, db=db)).model_dump(), + **knowledge.model_dump(), files=await Knowledges.get_file_metadatas_by_id(id, db=db), ) @@ -826,7 +826,11 @@ async def remove_file_from_knowledge_by_id( log.debug(e) pass - if delete_file: + # Only the file owner or an admin may permanently delete the underlying + # file. Collaborators with KB write access can unlink a file from the + # knowledge base but must not be able to destroy files they do not own, + # as the same file may be referenced by other KBs and chats. + if delete_file and (file.user_id == user.id or user.role == 'admin'): try: # Remove the file's collection from vector database file_collection = f'file-{form_data.file_id}' @@ -901,16 +905,7 @@ async def delete_knowledge_by_id( if len(updated_knowledge) != len(knowledge_list): log.info(f'Updating model {model.id} to remove knowledge base {id}') model.meta.knowledge = updated_knowledge - # Create a ModelForm for the update - model_form = ModelForm( - id=model.id, - name=model.name, - base_model_id=model.base_model_id, - meta=model.meta, - params=model.params, - access_grants=model.access_grants, - is_active=model.is_active, - ) + model_form = ModelForm(**model.model_dump()) await Models.update_model_by_id(model.id, model_form, db=db) # Clean up vector DB diff --git a/backend/open_webui/routers/memories.py b/backend/open_webui/routers/memories.py index 3a42801d01..6522118258 100644 --- a/backend/open_webui/routers/memories.py +++ b/backend/open_webui/routers/memories.py @@ -144,6 +144,38 @@ async def query_memory( limit=form_data.k, ) + # Filter results by relevance threshold to avoid returning unrelated + # memories. Vector similarity search always returns the top-K nearest + # neighbours even when they are completely irrelevant; applying the + # same RELEVANCE_THRESHOLD used by RAG ensures only genuinely matching + # memories are surfaced (distances are normalised to 0→1, higher is + # better). + relevance_threshold = getattr(request.app.state.config, 'RELEVANCE_THRESHOLD', 0.0) + if results and relevance_threshold > 0.0 and results.distances and results.distances[0]: + from open_webui.retrieval.vector.main import SearchResult + + filtered_ids = [] + filtered_docs = [] + filtered_metas = [] + filtered_dists = [] + + for idx, score in enumerate(results.distances[0]): + if score >= relevance_threshold: + if results.ids and results.ids[0]: + filtered_ids.append(results.ids[0][idx]) + if results.documents and results.documents[0]: + filtered_docs.append(results.documents[0][idx]) + if results.metadatas and results.metadatas[0]: + filtered_metas.append(results.metadatas[0][idx]) + filtered_dists.append(score) + + results = SearchResult( + ids=[filtered_ids] if filtered_ids else [[]], + documents=[filtered_docs] if filtered_docs else [[]], + metadatas=[filtered_metas] if filtered_metas else [[]], + distances=[filtered_dists] if filtered_dists else [[]], + ) + return results diff --git a/backend/open_webui/routers/models.py b/backend/open_webui/routers/models.py index b7d31321ff..3ef0838fcc 100644 --- a/backend/open_webui/routers/models.py +++ b/backend/open_webui/routers/models.py @@ -281,24 +281,71 @@ async def import_models( model.id: model for model in (await Models.get_models_by_ids(model_ids, db=db) if model_ids else []) } + # Batch-resolve write permissions in one query instead of + # per-model has_access calls (N+1 avoidance). + existing_model_ids = list(existing_models.keys()) + if user.role != 'admin' and existing_model_ids: + groups = await Groups.get_groups_by_member_id(user.id, db=db) + user_group_ids = {group.id for group in groups} + writable_model_ids = await AccessGrants.get_accessible_resource_ids( + user_id=user.id, + resource_type='model', + resource_ids=existing_model_ids, + permission='write', + user_group_ids=user_group_ids, + db=db, + ) + else: + writable_model_ids = set(existing_model_ids) + for model_data in data: - # Here, you can add logic to validate model_data if needed model_id = model_data.get('id') if model_id and is_valid_model_id(model_id): existing_model = existing_models.get(model_id) if existing_model: + # Enforce ownership/write-access before allowing overwrite + if ( + user.role != 'admin' + and existing_model.user_id != user.id + and model_id not in writable_model_ids + ): + log.warning( + 'import_models: user %s skipped model %s (no write access)', + user.id, + model_id, + ) + continue + # Update existing model model_data['meta'] = model_data.get('meta', {}) model_data['params'] = model_data.get('params', {}) updated_model = ModelForm(**{**existing_model.model_dump(), **model_data}) + # Only filter access_grants when explicitly provided + # in the payload to avoid altering existing ACLs on + # metadata-only imports. + if 'access_grants' in model_data: + updated_model.access_grants = await filter_allowed_access_grants( + request.app.state.config.USER_PERMISSIONS, + user.id, + user.role, + updated_model.access_grants, + 'sharing.public_models', + ) await Models.update_model_by_id(model_id, updated_model, db=db) else: # Insert new model model_data['meta'] = model_data.get('meta', {}) model_data['params'] = model_data.get('params', {}) new_model = ModelForm(**model_data) + new_model.access_grants = await filter_allowed_access_grants( + request.app.state.config.USER_PERMISSIONS, + user.id, + user.role, + new_model.access_grants, + 'sharing.public_models', + ) await Models.insert_new_model(user_id=user.id, form_data=new_model, db=db) return True else: @@ -384,8 +431,12 @@ async def get_model_by_id(id: str, user=Depends(get_verified_user), db: AsyncSes @router.get('/model/profile/image') -async def get_model_profile_image(id: str, user=Depends(get_verified_user)): - model = await Models.get_model_by_id(id) +async def get_model_profile_image( + id: str, + user=Depends(get_verified_user), + db: AsyncSession = Depends(get_async_session), +): + model = await Models.get_model_by_id(id, db=db) if model: etag = f'"{model.updated_at}"' if model.updated_at else None diff --git a/backend/open_webui/routers/ollama.py b/backend/open_webui/routers/ollama.py index 9272db1e6a..b957310b58 100644 --- a/backend/open_webui/routers/ollama.py +++ b/backend/open_webui/routers/ollama.py @@ -1383,29 +1383,9 @@ async def generate_responses( if model_info.base_model_id: payload['model'] = model_info.base_model_id - # Check if user has access to the model - if user.role == 'user': - user_group_ids = {group.id for group in await Groups.get_groups_by_member_id(user.id)} - if not ( - user.id == model_info.user_id - or await AccessGrants.has_access( - user_id=user.id, - resource_type='model', - resource_id=model_info.id, - permission='read', - user_group_ids=user_group_ids, - ) - ): - raise HTTPException( - status_code=403, - detail=ERROR_MESSAGES.MODEL_NOT_FOUND(), - ) + await check_model_access(user, model_info) else: - if user.role != 'admin': - raise HTTPException( - status_code=403, - detail=ERROR_MESSAGES.MODEL_NOT_FOUND(), - ) + await check_model_access(user, None) url, url_idx = await get_ollama_url(request, payload['model'], url_idx) api_config = request.app.state.config.OLLAMA_API_CONFIGS.get( diff --git a/backend/open_webui/routers/openai.py b/backend/open_webui/routers/openai.py index 82c844afba..8a7c3aca72 100644 --- a/backend/open_webui/routers/openai.py +++ b/backend/open_webui/routers/openai.py @@ -1296,6 +1296,7 @@ async def embeddings(request: Request, form_data: dict, user): headers=headers, cookies=cookies, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT), + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) if 'text/event-stream' in r.headers.get('Content-Type', ''): diff --git a/backend/open_webui/routers/pipelines.py b/backend/open_webui/routers/pipelines.py index 94c1357fd7..580fb42fb2 100644 --- a/backend/open_webui/routers/pipelines.py +++ b/backend/open_webui/routers/pipelines.py @@ -94,9 +94,24 @@ async def process_pipeline_inlet_filter(request, payload, user, models): response.raise_for_status() payload = await response.json() except aiohttp.ClientResponseError as e: - res = await response.json() if response.content_type == 'application/json' else {} - if 'detail' in res: - raise Exception(response.status, res['detail']) + try: + res = await response.json() if 'application/json' in response.content_type else {} + if 'detail' in res: + raise HTTPException( + status_code=response.status, + detail=res['detail'], + ) + except HTTPException: + raise + except Exception: + pass + + raise HTTPException( + status_code=response.status, + detail=e.message, + ) + except HTTPException: + raise except Exception as e: log.exception(f'Connection error: {e}') @@ -146,9 +161,21 @@ async def process_pipeline_outlet_filter(request, payload, user, models): try: res = await response.json() if 'application/json' in response.content_type else {} if 'detail' in res: - raise Exception(response.status, res) + raise HTTPException( + status_code=response.status, + detail=res['detail'], + ) + except HTTPException: + raise except Exception: pass + + raise HTTPException( + status_code=response.status, + detail=e.message, + ) + except HTTPException: + raise except Exception as e: log.exception(f'Connection error: {e}') diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index 89ef452acf..48240ffe1f 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -48,7 +48,7 @@ from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT from open_webui.retrieval.vector.async_client import ASYNC_VECTOR_DB_CLIENT # Document loaders -from open_webui.retrieval.loaders.main import Loader + from open_webui.retrieval.loaders.youtube import YoutubeLoader # Web search engines @@ -82,6 +82,8 @@ from open_webui.retrieval.web.yandex import search_yandex from open_webui.retrieval.web.ydc import search_youcom from open_webui.retrieval.utils import ( + build_loader_from_config, + filter_accessible_collections, get_content_from_url, get_embedding_function, get_reranking_function, @@ -489,6 +491,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)): # Reranking settings 'RAG_RERANKING_MODEL': request.app.state.config.RAG_RERANKING_MODEL, 'RAG_RERANKING_ENGINE': request.app.state.config.RAG_RERANKING_ENGINE, + 'RAG_RERANKING_BATCH_SIZE': request.app.state.config.RAG_RERANKING_BATCH_SIZE, 'RAG_EXTERNAL_RERANKER_URL': request.app.state.config.RAG_EXTERNAL_RERANKER_URL, 'RAG_EXTERNAL_RERANKER_API_KEY': request.app.state.config.RAG_EXTERNAL_RERANKER_API_KEY, 'RAG_EXTERNAL_RERANKER_TIMEOUT': request.app.state.config.RAG_EXTERNAL_RERANKER_TIMEOUT, @@ -698,6 +701,7 @@ class ConfigForm(BaseModel): # Reranking settings RAG_RERANKING_MODEL: Optional[str] = None RAG_RERANKING_ENGINE: Optional[str] = None + RAG_RERANKING_BATCH_SIZE: Optional[int] = None RAG_EXTERNAL_RERANKER_URL: Optional[str] = None RAG_EXTERNAL_RERANKER_API_KEY: Optional[str] = None RAG_EXTERNAL_RERANKER_TIMEOUT: Optional[str] = None @@ -954,6 +958,12 @@ async def update_rag_config(request: Request, form_data: ConfigForm, user=Depend else request.app.state.config.RAG_EXTERNAL_RERANKER_TIMEOUT ) + request.app.state.config.RAG_RERANKING_BATCH_SIZE = ( + form_data.RAG_RERANKING_BATCH_SIZE + if form_data.RAG_RERANKING_BATCH_SIZE is not None + else request.app.state.config.RAG_RERANKING_BATCH_SIZE + ) + log.info( f'Updating reranking model: {request.app.state.config.RAG_RERANKING_MODEL} to {form_data.RAG_RERANKING_MODEL}' ) @@ -981,6 +991,7 @@ async def update_rag_config(request: Request, form_data: ConfigForm, user=Depend request.app.state.config.RAG_RERANKING_ENGINE, request.app.state.config.RAG_RERANKING_MODEL, request.app.state.rf, + reranking_batch_size=request.app.state.config.RAG_RERANKING_BATCH_SIZE, ) except Exception as e: log.error(f'Error loading reranking model: {e}') @@ -1629,41 +1640,8 @@ async def process_file( file_path = file.path if file_path: file_path = await asyncio.to_thread(Storage.get_file, file_path) - loader = Loader( - engine=request.app.state.config.CONTENT_EXTRACTION_ENGINE, - user=user, - DATALAB_MARKER_API_KEY=request.app.state.config.DATALAB_MARKER_API_KEY, - DATALAB_MARKER_API_BASE_URL=request.app.state.config.DATALAB_MARKER_API_BASE_URL, - DATALAB_MARKER_ADDITIONAL_CONFIG=request.app.state.config.DATALAB_MARKER_ADDITIONAL_CONFIG, - DATALAB_MARKER_SKIP_CACHE=request.app.state.config.DATALAB_MARKER_SKIP_CACHE, - DATALAB_MARKER_FORCE_OCR=request.app.state.config.DATALAB_MARKER_FORCE_OCR, - DATALAB_MARKER_PAGINATE=request.app.state.config.DATALAB_MARKER_PAGINATE, - DATALAB_MARKER_STRIP_EXISTING_OCR=request.app.state.config.DATALAB_MARKER_STRIP_EXISTING_OCR, - DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION=request.app.state.config.DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION, - DATALAB_MARKER_FORMAT_LINES=request.app.state.config.DATALAB_MARKER_FORMAT_LINES, - DATALAB_MARKER_USE_LLM=request.app.state.config.DATALAB_MARKER_USE_LLM, - DATALAB_MARKER_OUTPUT_FORMAT=request.app.state.config.DATALAB_MARKER_OUTPUT_FORMAT, - EXTERNAL_DOCUMENT_LOADER_URL=request.app.state.config.EXTERNAL_DOCUMENT_LOADER_URL, - EXTERNAL_DOCUMENT_LOADER_API_KEY=request.app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY, - TIKA_SERVER_URL=request.app.state.config.TIKA_SERVER_URL, - DOCLING_SERVER_URL=request.app.state.config.DOCLING_SERVER_URL, - DOCLING_API_KEY=request.app.state.config.DOCLING_API_KEY, - DOCLING_PARAMS=request.app.state.config.DOCLING_PARAMS, - PDF_EXTRACT_IMAGES=request.app.state.config.PDF_EXTRACT_IMAGES, - PDF_LOADER_MODE=request.app.state.config.PDF_LOADER_MODE, - DOCUMENT_INTELLIGENCE_ENDPOINT=request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT, - DOCUMENT_INTELLIGENCE_KEY=request.app.state.config.DOCUMENT_INTELLIGENCE_KEY, - DOCUMENT_INTELLIGENCE_MODEL=request.app.state.config.DOCUMENT_INTELLIGENCE_MODEL, - MISTRAL_OCR_API_BASE_URL=request.app.state.config.MISTRAL_OCR_API_BASE_URL, - MISTRAL_OCR_API_KEY=request.app.state.config.MISTRAL_OCR_API_KEY, - MISTRAL_OCR_USE_BASE64=request.app.state.config.MISTRAL_OCR_USE_BASE64, - MISTRAL_OCR_MODEL=request.app.state.config.MISTRAL_OCR_MODEL, - MINERU_API_MODE=request.app.state.config.MINERU_API_MODE, - MINERU_API_URL=request.app.state.config.MINERU_API_URL, - MINERU_API_KEY=request.app.state.config.MINERU_API_KEY, - MINERU_API_TIMEOUT=request.app.state.config.MINERU_API_TIMEOUT, - MINERU_PARAMS=request.app.state.config.MINERU_PARAMS, - ) + loader = build_loader_from_config(request) + loader.user = user docs = await loader.aload(file.filename, file.meta.get('content_type'), file_path) docs = [ @@ -1809,6 +1787,8 @@ async def process_text( collection_name = form_data.collection_name if collection_name is None: collection_name = calculate_sha256_string(form_data.content) + else: + await _validate_collection_access([collection_name], user, access_type='write') docs = [ Document( @@ -1850,6 +1830,8 @@ async def process_web( collection_name = form_data.collection_name if not collection_name: collection_name = calculate_sha256_string(form_data.url)[:63] + else: + await _validate_collection_access([collection_name], user, access_type='write') if not request.app.state.config.BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL: await run_in_threadpool( @@ -2353,32 +2335,20 @@ async def process_web_search(request: Request, form_data: SearchForm, user=Depen ) -async def _validate_collection_access(collection_names: list[str], user) -> None: +async def _validate_collection_access(collection_names: list[str], user, access_type: str = 'read') -> None: """ - Prevent users from querying collections they don't own. - Enforces ownership on user-memory-* and file-* collections. - Admins bypass this check. + Raise 403 if the user lacks access to any of the requested collections. + Delegates to the shared filter_accessible_collections utility so the + access rules stay in one place. """ - if user.role == 'admin': - return - - for name in collection_names: - if name.startswith('user-memory-') and name != f'user-memory-{user.id}': - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail=ERROR_MESSAGES.ACCESS_PROHIBITED, - ) - elif name.startswith('file-'): - file_id = name[len('file-') :] - if not await has_access_to_file( - file_id=file_id, - access_type='read', - user=user, - ): - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail=ERROR_MESSAGES.ACCESS_PROHIBITED, - ) + requested = set(collection_names) + allowed = await filter_accessible_collections(requested, user, access_type=access_type) + denied = requested - allowed + if denied: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) class QueryDocForm(BaseModel): diff --git a/backend/open_webui/routers/terminals.py b/backend/open_webui/routers/terminals.py index 0d607d1f78..003db06968 100644 --- a/backend/open_webui/routers/terminals.py +++ b/backend/open_webui/routers/terminals.py @@ -16,6 +16,7 @@ from starlette.background import BackgroundTask from open_webui.utils.auth import get_verified_user from open_webui.utils.access_control import has_connection_access +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL from open_webui.models.groups import Groups from open_webui.models.users import Users @@ -141,6 +142,7 @@ async def proxy_terminal( headers=headers, cookies=cookies, data=body or None, + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) upstream_content_type = upstream_response.headers.get('content-type', '') @@ -279,7 +281,7 @@ async def ws_terminal( session = aiohttp.ClientSession() try: - async with session.ws_connect(upstream_url) as upstream: + async with session.ws_connect(upstream_url, ssl=AIOHTTP_CLIENT_SESSION_SSL) as upstream: import asyncio import json as _json diff --git a/backend/open_webui/routers/tools.py b/backend/open_webui/routers/tools.py index d70b4038fe..04d845c3de 100644 --- a/backend/open_webui/routers/tools.py +++ b/backend/open_webui/routers/tools.py @@ -4,7 +4,7 @@ from typing import Optional import time import re import aiohttp -from open_webui.env import AIOHTTP_CLIENT_TIMEOUT +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT from open_webui.models.groups import Groups from pydantic import BaseModel, HttpUrl from fastapi import APIRouter, Depends, HTTPException, Request, status @@ -274,7 +274,9 @@ async def load_tool_from_url(request: Request, form_data: LoadUrlForm, user=Depe async with aiohttp.ClientSession( trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) ) as session: - async with session.get(url, headers={'Content-Type': 'application/json'}) as resp: + async with session.get( + url, headers={'Content-Type': 'application/json'}, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.status != 200: raise HTTPException(status_code=resp.status, detail='Failed to fetch the tool') data = await resp.text() diff --git a/backend/open_webui/routers/users.py b/backend/open_webui/routers/users.py index 9fd2479ada..9dec855e45 100644 --- a/backend/open_webui/routers/users.py +++ b/backend/open_webui/routers/users.py @@ -14,7 +14,7 @@ from open_webui.models.auths import Auths from open_webui.models.oauth_sessions import OAuthSessions from open_webui.models.groups import Groups -from open_webui.models.chats import Chats + from open_webui.models.users import ( UserModel, UserGroupIdsModel, @@ -276,14 +276,8 @@ async def update_default_user_permissions(request: Request, form_data: UserPermi async def get_user_settings_by_session_user( user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session) ): - user = await Users.get_user_by_id(user.id, db=db) - if user: - return user.settings - else: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.USER_NOT_FOUND, - ) + # user already fetched by get_verified_user — no need to refetch + return user.settings ############################ @@ -339,14 +333,8 @@ async def get_user_status_by_session_user( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACTION_PROHIBITED, ) - user = await Users.get_user_by_id(user.id, db=db) - if user: - return user - else: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.USER_NOT_FOUND, - ) + # user already fetched by get_verified_user — no need to refetch + return user ############################ @@ -366,15 +354,14 @@ async def update_user_status_by_session_user( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACTION_PROHIBITED, ) - user = await Users.get_user_by_id(user.id, db=db) - if user: - user = await Users.update_user_status_by_id(user.id, form_data, db=db) - return user - else: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.USER_NOT_FOUND, - ) + # user already fetched by get_verified_user — no need to refetch + updated = await Users.update_user_status_by_id(user.id, form_data, db=db) + if updated: + return updated + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=ERROR_MESSAGES.USER_NOT_FOUND, + ) ############################ @@ -384,14 +371,8 @@ async def update_user_status_by_session_user( @router.get('/user/info', response_model=Optional[dict]) async def get_user_info_by_session_user(user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session)): - user = await Users.get_user_by_id(user.id, db=db) - if user: - return user.info - else: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.USER_NOT_FOUND, - ) + # user already fetched by get_verified_user — no need to refetch + return user.info ############################ @@ -403,19 +384,13 @@ async def get_user_info_by_session_user(user=Depends(get_verified_user), db: Asy async def update_user_info_by_session_user( form_data: dict, user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session) ): - user = await Users.get_user_by_id(user.id, db=db) - if user: - if user.info is None: - user.info = {} - - user = await Users.update_user_by_id(user.id, {'info': {**user.info, **form_data}}, db=db) - if user: - return user.info - else: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.USER_NOT_FOUND, - ) + # Merges against the auth-time snapshot of user.info. The previous pre-merge + # refetch only narrowed (did not eliminate) the lost-update window on concurrent + # same-user writes; real safety needs row locking or a version column. + existing_info = user.info or {} + updated = await Users.update_user_by_id(user.id, {'info': {**existing_info, **form_data}}, db=db) + if updated: + return updated.info else: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -439,18 +414,6 @@ class UserActiveResponse(UserStatus): @router.get('/{user_id}', response_model=UserActiveResponse) async def get_user_by_id(user_id: str, user=Depends(get_admin_user), db: AsyncSession = Depends(get_async_session)): - # Check if user_id is a shared chat - # If it is, get the user_id from the chat - if user_id.startswith('shared-'): - chat_id = user_id.replace('shared-', '') - chat = await Chats.get_chat_by_id(chat_id) - if chat: - user_id = chat.user_id - else: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.USER_NOT_FOUND, - ) user = await Users.get_user_by_id(user_id, db=db) if user: diff --git a/backend/open_webui/socket/main.py b/backend/open_webui/socket/main.py index 2c44eb25c5..e224408742 100644 --- a/backend/open_webui/socket/main.py +++ b/backend/open_webui/socket/main.py @@ -697,6 +697,31 @@ async def yjs_document_update(sid, data): log.warning(f'Session {sid} not in room {room}. Rejecting update.') return + # Verify write permission — room membership only proves read access + user = SESSION_POOL.get(sid) + if not user: + return + + if document_id.startswith('note:'): + note_id = document_id.split(':')[1] + note = await Notes.get_note_by_id(note_id) + if not note: + log.error(f'Note {note_id} not found') + return + + if ( + user.get('role') != 'admin' + and user.get('id') != note.user_id + and not await AccessGrants.has_access( + user_id=user.get('id'), + resource_type='note', + resource_id=note.id, + permission='write', + ) + ): + log.warning(f'User {user.get("id")} does not have write access to note {note_id}. Rejecting update.') + return + try: await stop_item_tasks(REDIS, document_id) except Exception: @@ -724,10 +749,6 @@ async def yjs_document_update(sid, data): skip_sid=sid, ) - user = SESSION_POOL.get(sid) - if not user: - return - async def debounced_save(): await asyncio.sleep(0.5) await document_save_handler(document_id, data.get('data', {}), user) @@ -743,7 +764,7 @@ async def yjs_document_update(sid, data): async def yjs_document_leave(sid, data): """Handle user leaving a document""" try: - document_id = data['document_id'] + document_id = normalize_document_id(data['document_id']) user_id = data.get('user_id', sid) log.info(f'User {user_id} leaving document {document_id}') diff --git a/backend/open_webui/static/favicon.ico b/backend/open_webui/static/favicon.ico index 14c5f9c6d4..b819d42f96 100644 Binary files a/backend/open_webui/static/favicon.ico and b/backend/open_webui/static/favicon.ico differ diff --git a/backend/open_webui/static/favicon.png b/backend/open_webui/static/favicon.png index 63735ad461..10c84f440c 100644 Binary files a/backend/open_webui/static/favicon.png and b/backend/open_webui/static/favicon.png differ diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 8aa27520f3..afa3cb63a9 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -56,19 +56,30 @@ async def get_current_timestamp( """ Get the current Unix timestamp in seconds. - :return: JSON with current_timestamp (seconds) and current_iso (ISO format) + :return: JSON with current_timestamp (seconds), current_iso (UTC ISO format), and user_local_iso (user's local time) """ try: import datetime + from zoneinfo import ZoneInfo now = datetime.datetime.now(datetime.timezone.utc) - return json.dumps( - { - 'current_timestamp': int(now.timestamp()), - 'current_iso': now.isoformat(), - }, - ensure_ascii=False, - ) + result = { + 'current_timestamp': int(now.timestamp()), + 'current_iso': now.isoformat(), + } + + # Include the user's local time if timezone is available + tz_name = __user__.get('timezone') if __user__ else None + if tz_name: + try: + user_tz = ZoneInfo(tz_name) + user_now = now.astimezone(user_tz) + result['user_local_iso'] = user_now.isoformat() + result['user_timezone'] = tz_name + except Exception: + pass + + return json.dumps(result, ensure_ascii=False) except Exception as e: log.exception(f'get_current_timestamp error: {e}') return json.dumps({'error': str(e)}) @@ -110,15 +121,27 @@ async def calculate_timestamp( adjusted_ts = int(adjusted.timestamp()) - return json.dumps( - { - 'current_timestamp': current_ts, - 'current_iso': now.isoformat(), - 'calculated_timestamp': adjusted_ts, - 'calculated_iso': adjusted.isoformat(), - }, - ensure_ascii=False, - ) + result = { + 'current_timestamp': current_ts, + 'current_iso': now.isoformat(), + 'calculated_timestamp': adjusted_ts, + 'calculated_iso': adjusted.isoformat(), + } + + # Include the user's local time if timezone is available + tz_name = __user__.get('timezone') if __user__ else None + if tz_name: + try: + from zoneinfo import ZoneInfo + + user_tz = ZoneInfo(tz_name) + result['user_local_iso'] = now.astimezone(user_tz).isoformat() + result['calculated_local_iso'] = adjusted.astimezone(user_tz).isoformat() + result['user_timezone'] = tz_name + except Exception: + pass + + return json.dumps(result, ensure_ascii=False) except ImportError: # Fallback without dateutil import datetime @@ -128,15 +151,26 @@ async def calculate_timestamp( total_days = days_ago + (weeks_ago * 7) + (months_ago * 30) + (years_ago * 365) adjusted = now - datetime.timedelta(days=total_days) adjusted_ts = int(adjusted.timestamp()) - return json.dumps( - { - 'current_timestamp': current_ts, - 'current_iso': now.isoformat(), - 'calculated_timestamp': adjusted_ts, - 'calculated_iso': adjusted.isoformat(), - }, - ensure_ascii=False, - ) + result = { + 'current_timestamp': current_ts, + 'current_iso': now.isoformat(), + 'calculated_timestamp': adjusted_ts, + 'calculated_iso': adjusted.isoformat(), + } + + tz_name = __user__.get('timezone') if __user__ else None + if tz_name: + try: + from zoneinfo import ZoneInfo + + user_tz = ZoneInfo(tz_name) + result['user_local_iso'] = now.astimezone(user_tz).isoformat() + result['calculated_local_iso'] = adjusted.astimezone(user_tz).isoformat() + result['user_timezone'] = tz_name + except Exception: + pass + + return json.dumps(result, ensure_ascii=False) except Exception as e: log.exception(f'calculate_timestamp error: {e}') return json.dumps({'error': str(e)}) @@ -2494,7 +2528,6 @@ async def create_automation( name: str, prompt: str, rrule: str, - model_id: Optional[str] = None, __request__: Request = None, __user__: dict = None, __metadata__: dict = None, @@ -2502,6 +2535,7 @@ async def create_automation( """ Create a scheduled automation that runs a prompt on a recurring or one-time schedule. Use this when the user wants to schedule a task to run automatically. + The automation will use the current chat model. The rrule parameter must be a valid iCalendar RRULE string. Common examples: - Every day at 9am: "DTSTART:20250101T090000\\nRRULE:FREQ=DAILY" @@ -2516,7 +2550,6 @@ async def create_automation( :param name: A short descriptive name for the automation :param prompt: The prompt/instructions to execute on each run :param rrule: An iCalendar RRULE string defining the schedule - :param model_id: Optional model ID to use. Defaults to the current chat model if omitted. :return: JSON with the created automation details including id, next scheduled runs """ if __request__ is None: @@ -2535,15 +2568,14 @@ async def create_automation( if not user: return json.dumps({'error': 'User not found'}) - # Default to current chat's model if not specified + # Always use the calling model for the automation + model_id = (__metadata__ or {}).get('model_id') if not model_id: - model_id = (__metadata__ or {}).get('model_id') or (__metadata__ or {}).get('model') - if not model_id: - return json.dumps({'error': 'model_id is required (could not detect current model)'}) + return json.dumps({'error': 'Could not detect current model'}) # Validate the RRULE try: - validate_rrule(rrule) + validate_rrule(rrule, tz=user.timezone) except ValueError as e: return json.dumps({'error': f'Invalid schedule: {e}'}) @@ -2624,7 +2656,7 @@ async def update_automation( # Validate RRULE if changed if rrule is not None: try: - validate_rrule(new_rrule) + validate_rrule(new_rrule, tz=user.timezone if user else None) except ValueError as e: return json.dumps({'error': f'Invalid schedule: {e}'}) @@ -2812,3 +2844,424 @@ async def delete_automation( except Exception as e: log.exception(f'delete_automation error: {e}') return json.dumps({'error': str(e)}) + + +# ============================================================================= +# CALENDAR TOOLS +# ============================================================================= + + +def _get_user_tz(user_dict: dict): + """Get the user's timezone as a ZoneInfo, falling back to UTC.""" + from zoneinfo import ZoneInfo + + tz_name = None + if user_dict: + tz_name = user_dict.get('timezone') + if tz_name: + try: + return ZoneInfo(tz_name) + except Exception: + pass + return ZoneInfo('UTC') + + +def _dt_to_ns(dt_str: str, tz) -> int: + """Convert a datetime string to nanoseconds since epoch, interpreting in the given timezone.""" + from datetime import datetime + + dt = datetime.fromisoformat(dt_str) + # If naive (no timezone info), localize to user's timezone + if dt.tzinfo is None: + dt = dt.replace(tzinfo=tz) + return int(dt.timestamp() * 1_000) * 1_000_000 + + +def _ns_to_dt(ns: int, tz) -> str: + """Convert nanoseconds since epoch to a datetime string in the given timezone.""" + from datetime import datetime + + seconds = ns / 1_000_000_000 + dt = datetime.fromtimestamp(seconds, tz=tz) + return dt.strftime('%Y-%m-%d %H:%M') + + +def _event_to_dict(event, tz) -> dict: + """Convert a calendar event model to a human-friendly dict with local timestamps.""" + return { + 'id': event.id, + 'calendar_id': event.calendar_id, + 'title': event.title, + 'description': event.description or '', + 'start': _ns_to_dt(event.start_at, tz), + 'end': _ns_to_dt(event.end_at, tz) if event.end_at else None, + 'all_day': event.all_day, + 'location': event.location or '', + 'color': event.color, + 'is_cancelled': event.is_cancelled, + } + + +async def search_calendar_events( + query: Optional[str] = None, + start: Optional[str] = None, + end: Optional[str] = None, + count: int = 10, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Search calendar events by text and/or date range. + Returns matching events across all accessible calendars. + + :param query: Search text to match against event title, description, or location (optional) + :param start: Only return events starting at or after this datetime, e.g. "2026-04-20 00:00" (optional) + :param end: Only return events starting before this datetime, e.g. "2026-04-27 00:00" (optional) + :param count: Maximum number of events to return (default: 10) + :return: JSON list of matching events with id, title, description, start, end, calendar_id, location + """ + if __request__ is None: + return json.dumps({'error': 'Request context not available'}) + + if not __user__: + return json.dumps({'error': 'User context not available'}) + + try: + from open_webui.models.calendar import CalendarEvents + + user_id = __user__.get('id') + tz = _get_user_tz(__user__) + + if isinstance(count, str): + try: + count = int(count) + except ValueError: + count = 10 + + if start or end: + # Date range query — use get_events_by_range + try: + start_ns = _dt_to_ns(start, tz) if start else 0 + except (ValueError, TypeError) as e: + return json.dumps({'error': f'Invalid start datetime: {e}'}) + + try: + end_ns = ( + _dt_to_ns(end, tz) + if end + else int(time.time() * 1_000) * 1_000_000 + 365 * 86400 * 1_000_000_000_000 + ) + except (ValueError, TypeError) as e: + return json.dumps({'error': f'Invalid end datetime: {e}'}) + + items = await CalendarEvents.get_events_by_range( + user_id=user_id, + start=start_ns, + end=end_ns, + ) + + # Apply text filter if query is also provided + if query: + q = query.lower() + items = [ + e + for e in items + if q in (e.title or '').lower() + or q in (e.description or '').lower() + or q in (e.location or '').lower() + ] + + events = [_event_to_dict(item, tz) for item in items[:count]] + return json.dumps( + {'events': events, 'total': len(items)}, + ensure_ascii=False, + ) + else: + # Text-only search + result = await CalendarEvents.search_events( + user_id=user_id, + query=query, + skip=0, + limit=count, + ) + + events = [_event_to_dict(item, tz) for item in result.items] + return json.dumps( + {'events': events, 'total': result.total}, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f'search_calendar_events error: {e}') + return json.dumps({'error': str(e)}) + + +async def create_calendar_event( + title: str, + start: str, + end: Optional[str] = None, + description: Optional[str] = None, + calendar_id: Optional[str] = None, + all_day: bool = False, + location: Optional[str] = None, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Create a new calendar event. If no calendar_id is provided, the event is + added to the user's default calendar. + + :param title: Event title + :param start: Start datetime string in your local time (e.g. "2026-04-20 09:00" or "2026-04-20T09:00:00") + :param end: End datetime string in your local time (optional, omit for point-in-time events) + :param description: Event description (optional) + :param calendar_id: Target calendar ID (optional, uses default calendar if omitted) + :param all_day: Whether this is an all-day event (default: false) + :param location: Event location (optional) + :return: JSON with the created event details including id + """ + if __request__ is None: + return json.dumps({'error': 'Request context not available'}) + + if not __user__: + return json.dumps({'error': 'User context not available'}) + + try: + from open_webui.models.calendar import Calendars, CalendarEvents, CalendarEventForm + + user_id = __user__.get('id') + + # Resolve calendar_id: use provided, or fall back to default + if not calendar_id: + calendars = await Calendars.get_calendars_by_user(user_id) + default_cal = next((c for c in calendars if c.is_default), None) + if not default_cal and calendars: + default_cal = calendars[0] + if not default_cal: + return json.dumps({'error': 'No calendars found. Cannot create event.'}) + calendar_id = default_cal.id + + # Verify access + cal = await Calendars.get_calendar_by_id(calendar_id) + if not cal: + return json.dumps({'error': 'Calendar not found'}) + if cal.user_id != user_id and __user__.get('role') != 'admin': + from open_webui.models.access_grants import AccessGrants + from open_webui.models.groups import Groups + + user_group_ids = [g.id for g in await Groups.get_groups_by_member_id(user_id)] + if not await AccessGrants.has_access( + user_id=user_id, + resource_type='calendar', + resource_id=cal.id, + permission='write', + user_group_ids=set(user_group_ids), + ): + return json.dumps({'error': 'Access denied to this calendar'}) + + # Coerce boolean from LLM + if isinstance(all_day, str): + all_day = all_day.lower() in ('true', '1', 'yes') + + # Convert datetime strings to nanoseconds using user's timezone + tz = _get_user_tz(__user__) + try: + start_ns = _dt_to_ns(start, tz) + except (ValueError, TypeError) as e: + return json.dumps({'error': f'Invalid start datetime: {e}. Use format like "2026-04-20 09:00"'}) + + end_ns = None + if end: + try: + end_ns = _dt_to_ns(end, tz) + except (ValueError, TypeError) as e: + return json.dumps({'error': f'Invalid end datetime: {e}. Use format like "2026-04-20 10:00"'}) + elif not all_day: + # Default to 1 hour duration + end_ns = start_ns + 3_600_000_000_000 + + form = CalendarEventForm( + calendar_id=calendar_id, + title=title, + description=description, + start_at=start_ns, + end_at=end_ns, + all_day=all_day, + location=location, + ) + + event = await CalendarEvents.insert_new_event(user_id, form) + if not event: + return json.dumps({'error': 'Failed to create event'}) + + return json.dumps( + { + 'status': 'success', + **_event_to_dict(event, tz), + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f'create_calendar_event error: {e}') + return json.dumps({'error': str(e)}) + + +async def update_calendar_event( + event_id: str, + title: Optional[str] = None, + description: Optional[str] = None, + start: Optional[str] = None, + end: Optional[str] = None, + all_day: Optional[bool] = None, + location: Optional[str] = None, + is_cancelled: Optional[bool] = None, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Update an existing calendar event. Only provided fields are changed; + omitted fields stay the same. + + :param event_id: The ID of the event to update + :param title: New event title (optional) + :param description: New event description (optional) + :param start: New start datetime string in your local time, e.g. "2026-04-20 09:00" (optional) + :param end: New end datetime string in your local time (optional) + :param all_day: Whether this is an all-day event (optional) + :param location: New event location (optional) + :param is_cancelled: Set to true to cancel the event (optional) + :return: JSON with the updated event details + """ + if __request__ is None: + return json.dumps({'error': 'Request context not available'}) + + if not __user__: + return json.dumps({'error': 'User context not available'}) + + try: + from open_webui.models.calendar import Calendars, CalendarEvents, CalendarEventUpdateForm + from open_webui.models.access_grants import AccessGrants + from open_webui.models.groups import Groups + + user_id = __user__.get('id') + + event = await CalendarEvents.get_event_by_id(event_id) + if not event: + return json.dumps({'error': 'Event not found'}) + + # Check write access to the event's calendar + cal = await Calendars.get_calendar_by_id(event.calendar_id) + if cal and cal.user_id != user_id and __user__.get('role') != 'admin': + user_group_ids = [g.id for g in await Groups.get_groups_by_member_id(user_id)] + if not await AccessGrants.has_access( + user_id=user_id, + resource_type='calendar', + resource_id=cal.id, + permission='write', + user_group_ids=set(user_group_ids), + ): + return json.dumps({'error': 'Access denied'}) + + # Coerce boolean strings from LLM + if isinstance(all_day, str): + all_day = all_day.lower() in ('true', '1', 'yes') + if isinstance(is_cancelled, str): + is_cancelled = is_cancelled.lower() in ('true', '1', 'yes') + + # Convert datetime strings to nanoseconds using user's timezone + tz = _get_user_tz(__user__) + start_ns = None + if start is not None: + try: + start_ns = _dt_to_ns(start, tz) + except (ValueError, TypeError) as e: + return json.dumps({'error': f'Invalid start datetime: {e}'}) + + end_ns = None + if end is not None: + try: + end_ns = _dt_to_ns(end, tz) + except (ValueError, TypeError) as e: + return json.dumps({'error': f'Invalid end datetime: {e}'}) + + form = CalendarEventUpdateForm( + title=title, + description=description, + start_at=start_ns, + end_at=end_ns, + all_day=all_day, + location=location, + is_cancelled=is_cancelled, + ) + + updated = await CalendarEvents.update_event_by_id(event_id, form) + if not updated: + return json.dumps({'error': 'Failed to update event'}) + + return json.dumps( + { + 'status': 'success', + **_event_to_dict(updated, tz), + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f'update_calendar_event error: {e}') + return json.dumps({'error': str(e)}) + + +async def delete_calendar_event( + event_id: str, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Delete a calendar event permanently. + + :param event_id: The ID of the event to delete + :return: JSON confirming the event was deleted + """ + if __request__ is None: + return json.dumps({'error': 'Request context not available'}) + + if not __user__: + return json.dumps({'error': 'User context not available'}) + + try: + from open_webui.models.calendar import Calendars, CalendarEvents + from open_webui.models.access_grants import AccessGrants + from open_webui.models.groups import Groups + + user_id = __user__.get('id') + + event = await CalendarEvents.get_event_by_id(event_id) + if not event: + return json.dumps({'error': 'Event not found'}) + + # Check write access + cal = await Calendars.get_calendar_by_id(event.calendar_id) + if cal and cal.user_id != user_id and __user__.get('role') != 'admin': + user_group_ids = [g.id for g in await Groups.get_groups_by_member_id(user_id)] + if not await AccessGrants.has_access( + user_id=user_id, + resource_type='calendar', + resource_id=cal.id, + permission='write', + user_group_ids=set(user_group_ids), + ): + return json.dumps({'error': 'Access denied'}) + + title = event.title + result = await CalendarEvents.delete_event_by_id(event_id) + if not result: + return json.dumps({'error': 'Failed to delete event'}) + + return json.dumps( + { + 'status': 'success', + 'message': f'Event "{title}" deleted', + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f'delete_calendar_event error: {e}') + return json.dumps({'error': str(e)}) diff --git a/backend/open_webui/utils/access_control/__init__.py b/backend/open_webui/utils/access_control/__init__.py index 41c888d441..06e8d0aba0 100644 --- a/backend/open_webui/utils/access_control/__init__.py +++ b/backend/open_webui/utils/access_control/__init__.py @@ -257,6 +257,47 @@ async def filter_allowed_access_grants( return access_grants +async def has_base_model_access( + user_id: str, + model_info, + *, + user_group_ids: set[str] | None = None, + db=None, +) -> bool: + """ + Walk the ``base_model_id`` chain and verify the caller has read access + at every hop. + + Returns ``True`` when access is granted (or the chain ends at a raw + provider model that has no per-model ACL). Returns ``False`` the + moment a registered base model denies access. + """ + from open_webui.models.models import Models + from open_webui.models.access_grants import AccessGrants + + base_model_id = getattr(model_info, 'base_model_id', None) + seen = {model_info.id} + while base_model_id and base_model_id not in seen: + seen.add(base_model_id) + base_model_info = await Models.get_model_by_id(base_model_id, db=db) + if base_model_info is None: + break # Raw provider model — no per-model ACL + if not ( + user_id == base_model_info.user_id + or await AccessGrants.has_access( + user_id=user_id, + resource_type='model', + resource_id=base_model_info.id, + permission='read', + user_group_ids=user_group_ids, + db=db, + ) + ): + return False + base_model_id = getattr(base_model_info, 'base_model_id', None) + return True + + async def check_model_access( user: UserModel, model_info, @@ -296,6 +337,10 @@ async def check_model_access( ) ): raise HTTPException(status_code=403, detail='Model not found') + + # Enforce access on chained base models + if not await has_base_model_access(user.id, model_info, user_group_ids=user_group_ids): + raise HTTPException(status_code=403, detail='Model not found') else: if user.role != 'admin': raise HTTPException(status_code=403, detail='Model not found') diff --git a/backend/open_webui/utils/access_control/files.py b/backend/open_webui/utils/access_control/files.py index 5e7efb5b26..a48dfeb0f1 100644 --- a/backend/open_webui/utils/access_control/files.py +++ b/backend/open_webui/utils/access_control/files.py @@ -66,10 +66,18 @@ async def has_access_to_file( return True # Check if the file is associated with any chats the user has access to - # TODO: Granular access control for chats - chats = await Chats.get_shared_chats_by_file_id(file_id, db=db) - if chats: - return True + shared_chat_ids = await Chats.get_shared_chat_ids_by_file_id(file_id, db=db) + if shared_chat_ids: + accessible_ids = await AccessGrants.get_accessible_resource_ids( + user_id=user.id, + resource_type='shared_chat', + resource_ids=shared_chat_ids, + permission='read', + user_group_ids=user_group_ids, + db=db, + ) + if accessible_ids: + return True # Check if the file is directly attached to a shared workspace model for model in await Models.get_models_by_user_id(user.id, permission=access_type, db=db): diff --git a/backend/open_webui/utils/automations.py b/backend/open_webui/utils/automations.py index 3866eb865a..95b931e320 100644 --- a/backend/open_webui/utils/automations.py +++ b/backend/open_webui/utils/automations.py @@ -1,11 +1,16 @@ """ -Automation utilities. +Automation utilities and unified scheduler. -RRULE helpers, worker loop, and execution logic. +RRULE helpers, scheduler worker loop, and execution logic. Follows the utils/.py pattern (cf. utils/channels.py, utils/task.py). +The scheduler_worker_loop handles all time-based background work: + - Automation execution (claim_due → execute) + - Calendar event alerts (upcoming events → socket + webhook notifications) + Environment: - AUTOMATION_POLL_INTERVAL – seconds between polls (default: 10) + SCHEDULER_POLL_INTERVAL – seconds between polls (default: 10) + CALENDAR_ALERT_LOOKAHEAD_MINUTES – default alert window (default: 5) """ import asyncio @@ -31,7 +36,8 @@ from open_webui.internal.db import get_async_db log = logging.getLogger(__name__) -AUTOMATION_POLL_INTERVAL = int(os.getenv('AUTOMATION_POLL_INTERVAL', '10')) +SCHEDULER_POLL_INTERVAL = int(os.getenv('SCHEDULER_POLL_INTERVAL', os.getenv('AUTOMATION_POLL_INTERVAL', '10'))) +CALENDAR_ALERT_LOOKAHEAD_MINUTES = int(os.getenv('CALENDAR_ALERT_LOOKAHEAD_MINUTES', '10')) #################### @@ -39,6 +45,22 @@ AUTOMATION_POLL_INTERVAL = int(os.getenv('AUTOMATION_POLL_INTERVAL', '10')) #################### +def _resolve_tz(tz: str = None) -> Optional[ZoneInfo]: + """Safely resolve a timezone string to ZoneInfo. + + Returns None (→ server-local fallback) when *tz* is empty, None, + or an unrecognised IANA key. Logs a warning on bad keys so + misconfiguration is visible in the server logs. + """ + if not tz: + return None + try: + return ZoneInfo(tz) + except (KeyError, Exception): + log.warning('Unknown timezone %r — falling back to server time', tz) + return None + + def _parse_rule(s: str): """Parse RRULE with clock-aligned DTSTART for sub-daily frequencies. @@ -55,38 +77,52 @@ def _parse_rule(s: str): return rrulestr(s, ignoretz=True) -def validate_rrule(s: str) -> None: - """Raise ValueError if the RRULE is malformed or exhausted.""" +def validate_rrule(s: str, tz: str = None) -> None: + """Raise ValueError if the RRULE is malformed or exhausted. + + When *tz* is provided the "now" reference uses the user's local + clock so that near-future schedules are not incorrectly rejected + on servers whose system clock is ahead (e.g. UTC vs US timezones). + """ try: rule = _parse_rule(s) except Exception as e: raise ValueError(ERROR_MESSAGES.AUTOMATION_INVALID_RRULE(e)) - if rule.after(datetime.now()) is None: + zi = _resolve_tz(tz) + now = datetime.now(zi).replace(tzinfo=None) if zi else datetime.now() + if rule.after(now) is None: raise ValueError(ERROR_MESSAGES.AUTOMATION_NO_FUTURE_RUNS) def next_run_ns(s: str, tz: str = None) -> Optional[int]: """Next occurrence as epoch nanoseconds, respecting user timezone.""" - now = datetime.now(ZoneInfo(tz)) if tz else datetime.now() + zi = _resolve_tz(tz) + now = datetime.now(zi) if zi else datetime.now() dt = _parse_rule(s).after(now.replace(tzinfo=None)) if dt is None: return None - if tz: - dt = dt.replace(tzinfo=ZoneInfo(tz)) + if zi: + dt = dt.replace(tzinfo=zi) return int(dt.timestamp() * 1_000_000_000) def next_n_runs_ns(s: str, n: int = 5, tz: str = None) -> list[int]: - """Compute next N occurrences for UI preview.""" + """Compute next N occurrences for UI preview. + + Uses the user's timezone for the starting "now" so that the + preview matches the user's local clock (same as next_run_ns). + """ + zi = _resolve_tz(tz) rule = _parse_rule(s) result = [] - dt = datetime.now() + now = datetime.now(zi).replace(tzinfo=None) if zi else datetime.now() + dt = now for _ in range(n): dt = rule.after(dt) if not dt: break - if tz: - dt_tz = dt.replace(tzinfo=ZoneInfo(tz)) + if zi: + dt_tz = dt.replace(tzinfo=zi) result.append(int(dt_tz.timestamp() * 1_000_000_000)) else: result.append(int(dt.timestamp() * 1_000_000_000)) @@ -117,26 +153,49 @@ def rrule_interval_seconds(s: str) -> Optional[int]: ############################ +# Keep the old name as an alias so any stale imports still work. async def automation_worker_loop(app) -> None: - """Poll for due automations, claim, fire-and-forget execute. + """Deprecated alias — use scheduler_worker_loop.""" + await scheduler_worker_loop(app) + + +async def scheduler_worker_loop(app) -> None: + """Unified background scheduler for all time-based work. + + Handles: + 1. Automation execution (ENABLE_AUTOMATIONS) + 2. Calendar event alerts (ENABLE_CALENDAR) Runs on every instance. Poll interval is configurable via - AUTOMATION_POLL_INTERVAL env var (default: 10 seconds). + SCHEDULER_POLL_INTERVAL env var (default: 10 seconds). """ - log.info(f'Automation worker started (poll interval: {AUTOMATION_POLL_INTERVAL}s)') + log.info(f'Scheduler worker started (poll interval: {SCHEDULER_POLL_INTERVAL}s)') while True: try: - async with get_async_db() as db: - batch = await Automations.claim_due(int(time.time_ns()), limit=10, db=db) - if batch: - log.info(f'Claimed {len(batch)} due automation(s)') - for automation in batch: - asyncio.create_task(execute_automation(app, automation)) + # ── Automations ── + if getattr(app.state.config, 'ENABLE_AUTOMATIONS', False): + try: + async with get_async_db() as db: + batch = await Automations.claim_due(int(time.time_ns()), limit=10, db=db) + if batch: + log.info(f'Claimed {len(batch)} due automation(s)') + for automation in batch: + asyncio.create_task(execute_automation(app, automation)) + except Exception: + log.exception('Scheduler: automation error') + + # ── Calendar Alerts ── + if getattr(app.state.config, 'ENABLE_CALENDAR', False): + try: + await _check_calendar_alerts(app) + except Exception: + log.exception('Scheduler: calendar alert error') + except Exception: - log.exception('Automation worker error') + log.exception('Scheduler worker error') # Jitter to spread load across instances - await asyncio.sleep(AUTOMATION_POLL_INTERVAL + random.uniform(0, 2)) + await asyncio.sleep(SCHEDULER_POLL_INTERVAL + random.uniform(0, 2)) ########################## @@ -243,6 +302,7 @@ async def _set_terminal_cwd(app, server_id: str, user, cwd: str, chat_id: str) - handled correctly — same path the frontend uses. """ import aiohttp + from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL connections = getattr(getattr(app, 'state', None), 'config', None) if connections is None: @@ -278,6 +338,7 @@ async def _set_terminal_cwd(app, server_id: str, user, cwd: str, chat_id: str) - target_url, json={'path': cwd}, headers=headers, + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as resp: if resp.status != 200: body = await resp.text() @@ -429,6 +490,98 @@ async def execute_automation(app, automation: AutomationModel) -> None: #################### +async def _check_calendar_alerts(app) -> None: + """Check for upcoming calendar events and send alert notifications. + + De-duplication is DB-backed via meta.alerted_at — survives restarts + and works across multiple instances. + """ + from open_webui.models.calendar import CalendarEvents, CalendarEventUpdateForm + from open_webui.socket.main import sio + + now_ns = int(time.time_ns()) + default_lookahead_ns = CALENDAR_ALERT_LOOKAHEAD_MINUTES * 60 * 1_000_000_000 + + async with get_async_db() as db: + upcoming = await CalendarEvents.get_upcoming_events(now_ns, default_lookahead_ns, db=db) + + if not upcoming: + return + + for event, user_tz in upcoming: + # Skip if already alerted for this start time + if event.meta and event.meta.get('alerted_at'): + continue + + # Compute minutes until event starts + minutes_until = max(0, int((event.start_at - now_ns) / (60 * 1_000_000_000))) + + alert_data = { + 'event_id': event.id, + 'title': event.title, + 'description': event.description or '', + 'start_at': event.start_at, + 'minutes_until': minutes_until, + 'calendar_id': event.calendar_id, + 'location': event.location or '', + } + + await sio.emit( + 'events', + { + 'data': { + 'type': 'calendar:alert', + 'data': alert_data, + }, + }, + room=f'user:{event.user_id}', + ) + + # Mark as alerted in DB so it survives restarts / multi-instance + try: + await CalendarEvents.update_event_by_id( + event.id, + CalendarEventUpdateForm(meta={'alerted_at': now_ns}), + ) + except Exception: + log.debug(f'Failed to mark event {event.id} as alerted', exc_info=True) + + # Send webhook notification if user has one configured + try: + webui_name = getattr(app.state, 'WEBUI_NAME', 'Open WebUI') + enable_user_webhooks = getattr(app.state.config, 'ENABLE_USER_WEBHOOKS', False) + + if enable_user_webhooks: + user = await Users.get_user_by_id(event.user_id) + if user and user.settings: + webhook_url = ( + user.settings.get('ui', {}).get('notifications', {}).get('webhook_url', None) + if isinstance(user.settings, dict) + else getattr(getattr(user.settings, 'ui', None), 'get', lambda *a: None)( + 'notifications', {} + ).get('webhook_url', None) + if hasattr(user.settings, 'ui') + else None + ) + if webhook_url: + from open_webui.utils.webhook import post_webhook + + time_str = f'in {minutes_until} min' if minutes_until > 0 else 'now' + await post_webhook( + webui_name, + webhook_url, + f'{event.title} — starting {time_str}', + { + 'action': 'calendar_alert', + 'title': event.title, + 'minutes_until': minutes_until, + 'event_id': event.id, + }, + ) + except Exception: + log.debug(f'Failed to send webhook for calendar alert {event.id}', exc_info=True) + + async def _record_run( automation_id: str, status: str, diff --git a/backend/open_webui/utils/calendar.py b/backend/open_webui/utils/calendar.py new file mode 100644 index 0000000000..9484c58dc0 --- /dev/null +++ b/backend/open_webui/utils/calendar.py @@ -0,0 +1,83 @@ +""" +Calendar utilities. + +RRULE expansion reusing the automation infra. +""" + +import logging +from datetime import datetime, timedelta +from typing import Optional +from zoneinfo import ZoneInfo + +from open_webui.utils.automations import _parse_rule + +log = logging.getLogger(__name__) + + +def expand_recurring_event( + event_dict: dict, + range_start_ns: int, + range_end_ns: int, + tz: Optional[str] = None, + max_instances: int = 5000, +) -> list[dict]: + """Expand a recurring event into individual instances within a date range. + + Takes an event dict (from CalendarEventModel.model_dump()) and produces + one dict per occurrence, with adjusted start_at / end_at. + """ + from dateutil.rrule import rrulestr + + rrule_str = event_dict.get('rrule') + if not rrule_str: + return [event_dict] + + range_start_dt = datetime.fromtimestamp(range_start_ns / 1_000_000_000) + range_end_dt = datetime.fromtimestamp(range_end_ns / 1_000_000_000) + scan_start = range_start_dt - timedelta(days=1) + + try: + # Parse with dtstart near the range so we never iterate from epoch + rule = rrulestr(rrule_str, dtstart=scan_start, ignoretz=True) + except Exception: + log.warning(f'Failed to parse RRULE for event {event_dict.get("id")}: {rrule_str}') + return [event_dict] + + original_start_ns = event_dict['start_at'] + original_end_ns = event_dict.get('end_at') + duration_ns = (original_end_ns - original_start_ns) if original_end_ns else None + + instances = [] + dt = rule.after(scan_start, inc=True) + + while dt and dt < range_end_dt and len(instances) < max_instances: + if tz: + try: + dt_tz = dt.replace(tzinfo=ZoneInfo(tz)) + instance_start_ns = int(dt_tz.timestamp() * 1_000_000_000) + except Exception: + instance_start_ns = int(dt.timestamp() * 1_000_000_000) + else: + instance_start_ns = int(dt.timestamp() * 1_000_000_000) + + if instance_start_ns >= range_start_ns: + instance = { + **event_dict, + 'start_at': instance_start_ns, + 'end_at': (instance_start_ns + duration_ns) if duration_ns else None, + 'instance_id': f'{event_dict["id"]}_{instance_start_ns}', + } + instances.append(instance) + + dt = rule.after(dt) + + return instances + + +def ns_from_date(year: int, month: int, day: int, tz: Optional[str] = None) -> int: + """Create epoch nanoseconds from a date.""" + if tz: + dt = datetime(year, month, day, tzinfo=ZoneInfo(tz)) + else: + dt = datetime(year, month, day) + return int(dt.timestamp() * 1_000_000_000) diff --git a/backend/open_webui/utils/chat.py b/backend/open_webui/utils/chat.py index 3539d57c86..9899469da9 100644 --- a/backend/open_webui/utils/chat.py +++ b/backend/open_webui/utils/chat.py @@ -10,7 +10,7 @@ import json import uuid import asyncio -from fastapi import Request, status +from fastapi import HTTPException, Request, status from starlette.responses import Response, StreamingResponse, JSONResponse @@ -328,6 +328,8 @@ async def chat_completed(request: Request, form_data: dict, user: Any): try: data = await process_pipeline_outlet_filter(request, data, user, models) + except HTTPException: + raise except Exception as e: raise Exception(f'Error: {e}') diff --git a/backend/open_webui/utils/files.py b/backend/open_webui/utils/files.py index eea3a8b486..8149987fe4 100644 --- a/backend/open_webui/utils/files.py +++ b/backend/open_webui/utils/files.py @@ -26,12 +26,29 @@ import base64 import io import re -from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK from open_webui.utils.session_pool import get_session BASE64_IMAGE_URL_PREFIX = re.compile(r'data:image/\w+;base64,', re.IGNORECASE) MARKDOWN_IMAGE_URL_PATTERN = re.compile(r'!\[(.*?)\]\((.+?)\)', re.IGNORECASE) +# Extension-based MIME fallback, only used when ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK is True. +_IMAGE_MIME_FALLBACK = { + '.webp': 'image/webp', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.gif': 'image/gif', + '.svg': 'image/svg+xml', + '.bmp': 'image/bmp', + '.tiff': 'image/tiff', + '.tif': 'image/tiff', + '.ico': 'image/x-icon', + '.heic': 'image/heic', + '.heif': 'image/heif', + '.avif': 'image/avif', +} + async def get_image_base64_from_url(url: str) -> Optional[str]: try: @@ -58,7 +75,11 @@ async def get_image_base64_from_url(url: str) -> Optional[str]: if file_path.is_file(): with open(file_path, 'rb') as image_file: encoded_string = base64.b64encode(image_file.read()).decode('utf-8') - content_type, _ = mimetypes.guess_type(file_path.name) + content_type = mimetypes.guess_type(file_path.name)[0] or (file.meta or {}).get('content_type') + if not content_type and ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK: + content_type = _IMAGE_MIME_FALLBACK.get(file_path.suffix.lower()) + if not content_type: + return None return f'data:{content_type};base64,{encoded_string}' else: return None @@ -71,7 +92,7 @@ async def get_image_url_from_base64(request, base64_image_string, metadata, user if BASE64_IMAGE_URL_PREFIX.match(base64_image_string): image_url = '' # Extract base64 image data from the line - image_data, content_type = get_image_data(base64_image_string) + image_data, content_type = await get_image_data(base64_image_string) if image_data is not None: _, image_url = await upload_image( request, @@ -178,11 +199,13 @@ async def get_image_base64_from_file_id(id: str) -> Optional[str]: # Check if the file already exists in the cache if file_path.is_file(): - import base64 - with open(file_path, 'rb') as image_file: encoded_string = base64.b64encode(image_file.read()).decode('utf-8') - content_type, _ = mimetypes.guess_type(file_path.name) + content_type = mimetypes.guess_type(file_path.name)[0] or (file.meta or {}).get('content_type') + if not content_type and ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK: + content_type = _IMAGE_MIME_FALLBACK.get(file_path.suffix.lower()) + if not content_type: + return None return f'data:{content_type};base64,{encoded_string}' else: return None diff --git a/backend/open_webui/utils/images/comfyui.py b/backend/open_webui/utils/images/comfyui.py index 497808c22d..9172f1c325 100644 --- a/backend/open_webui/utils/images/comfyui.py +++ b/backend/open_webui/utils/images/comfyui.py @@ -1,49 +1,51 @@ -import asyncio import json import logging import random -import requests -import aiohttp import urllib.parse -import urllib.request from typing import Optional -import websocket # NOTE: websocket-client (https://github.com/websocket-client/websocket-client) +import aiohttp from pydantic import BaseModel +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL +from open_webui.utils.session_pool import get_session + log = logging.getLogger(__name__) default_headers = {'User-Agent': 'Mozilla/5.0'} -def queue_prompt(prompt, client_id, base_url, api_key): +async def queue_prompt(prompt, client_id, base_url, api_key): log.info('queue_prompt') p = {'prompt': prompt, 'client_id': client_id} - data = json.dumps(p).encode('utf-8') - log.debug(f'queue_prompt data: {data}') + log.debug(f'queue_prompt data: {p}') try: - req = urllib.request.Request( + session = await get_session() + async with session.post( f'{base_url}/prompt', - data=data, + json=p, headers={**default_headers, 'Authorization': f'Bearer {api_key}'}, - ) - response = urllib.request.urlopen(req).read() - return json.loads(response) + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as r: + r.raise_for_status() + return await r.json() except Exception as e: log.exception(f'Error while queuing prompt: {e}') - raise e + raise -def get_image(filename, subfolder, folder_type, base_url, api_key): +async def get_image(filename, subfolder, folder_type, base_url, api_key): log.info('get_image') data = {'filename': filename, 'subfolder': subfolder, 'type': folder_type} url_values = urllib.parse.urlencode(data) - req = urllib.request.Request( + session = await get_session() + async with session.get( f'{base_url}/view?{url_values}', headers={**default_headers, 'Authorization': f'Bearer {api_key}'}, - ) - with urllib.request.urlopen(req) as response: - return response.read() + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as r: + r.raise_for_status() + return await r.read() def get_image_url(filename, subfolder, folder_type, base_url): @@ -53,32 +55,39 @@ def get_image_url(filename, subfolder, folder_type, base_url): return f'{base_url}/view?{url_values}' -def get_history(prompt_id, base_url, api_key): +async def get_history(prompt_id, base_url, api_key): log.info('get_history') - - req = urllib.request.Request( + session = await get_session() + async with session.get( f'{base_url}/history/{prompt_id}', headers={**default_headers, 'Authorization': f'Bearer {api_key}'}, - ) - with urllib.request.urlopen(req) as response: - return json.loads(response.read()) + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as r: + r.raise_for_status() + return await r.json() -def get_images(ws, workflow, client_id, base_url, api_key): - prompt_id = queue_prompt(workflow, client_id, base_url, api_key)['prompt_id'] +async def _ws_get_images(ws, workflow, client_id, base_url, api_key): + """Queue a prompt and wait on *ws* for ComfyUI to finish executing it. + + Returns a dict of ``{'data': [{'url': ...}, ...]}``. + """ + prompt_id = (await queue_prompt(workflow, client_id, base_url, api_key))['prompt_id'] output_images = [] - while True: - out = ws.recv() - if isinstance(out, str): - message = json.loads(out) + + async for msg in ws: + if msg.type == aiohttp.WSMsgType.TEXT: + message = json.loads(msg.data) if message['type'] == 'executing': data = message['data'] if data['node'] is None and data['prompt_id'] == prompt_id: break # Execution is done - else: - continue # previews are binary data + elif msg.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + log.error(f'WebSocket closed unexpectedly: {msg.type}') + break + # binary messages (previews) are silently skipped - history = get_history(prompt_id, base_url, api_key)[prompt_id] + history = (await get_history(prompt_id, base_url, api_key))[prompt_id] for node_id in history['outputs']: node_output = history['outputs'][node_id] if node_id in workflow and workflow[node_id].get('class_type') in [ @@ -105,10 +114,10 @@ async def comfyui_upload_image(image_file_item, base_url, api_key): form.add_field('image', file_bytes, filename=filename, content_type=mime_type) form.add_field('type', 'input') # required by ComfyUI - async with aiohttp.ClientSession() as session: - async with session.post(url, data=form, headers=headers) as resp: - resp.raise_for_status() - return await resp.json() + session = await get_session() + async with session.post(url, data=form, headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: + resp.raise_for_status() + return await resp.json() class ComfyUINodeInput(BaseModel): @@ -136,11 +145,9 @@ class ComfyUICreateImageForm(BaseModel): seed: Optional[int] = None -async def comfyui_create_image(model: str, payload: ComfyUICreateImageForm, client_id, base_url, api_key): - ws_url = base_url.replace('http://', 'ws://').replace('https://', 'wss://') - workflow = json.loads(payload.workflow.workflow) - - for node in payload.workflow.nodes: +def _apply_workflow_nodes(workflow, nodes, model, payload): + """Mutate *workflow* dict in-place based on typed node definitions.""" + for node in nodes: if node.type: if node.type == 'model': for node_id in node.node_ids: @@ -151,6 +158,14 @@ async def comfyui_create_image(model: str, payload: ComfyUICreateImageForm, clie elif node.type == 'negative_prompt': for node_id in node.node_ids: workflow[node_id]['inputs'][node.key if node.key else 'text'] = payload.negative_prompt + elif node.type == 'image': + if isinstance(payload.image, list): + for idx, node_id in enumerate(node.node_ids): + if idx < len(payload.image): + workflow[node_id]['inputs'][node.key] = payload.image[idx] + else: + for node_id in node.node_ids: + workflow[node_id]['inputs'][node.key] = payload.image elif node.type == 'width': for node_id in node.node_ids: workflow[node_id]['inputs'][node.key if node.key else 'width'] = payload.width @@ -171,24 +186,31 @@ async def comfyui_create_image(model: str, payload: ComfyUICreateImageForm, clie for node_id in node.node_ids: workflow[node_id]['inputs'][node.key] = node.value + +async def comfyui_create_image(model: str, payload: ComfyUICreateImageForm, client_id, base_url, api_key): + ws_url = base_url.replace('http://', 'ws://').replace('https://', 'wss://') + workflow = json.loads(payload.workflow.workflow) + _apply_workflow_nodes(workflow, payload.workflow.nodes, model, payload) + + headers = {'Authorization': f'Bearer {api_key}'} + session = await get_session() + try: - ws = websocket.WebSocket() - headers = {'Authorization': f'Bearer {api_key}'} - ws.connect(f'{ws_url}/ws?clientId={client_id}', header=headers) - log.info('WebSocket connection established.') - except Exception as e: + async with session.ws_connect( + f'{ws_url}/ws?clientId={client_id}', + headers=headers, + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as ws: + log.info('WebSocket connection established.') + log.info('Sending workflow to WebSocket server.') + log.info(f'Workflow: {workflow}') + images = await _ws_get_images(ws, workflow, client_id, base_url, api_key) + except aiohttp.WSServerHandshakeError as e: log.exception(f'Failed to connect to WebSocket server: {e}') return None - - try: - log.info('Sending workflow to WebSocket server.') - log.info(f'Workflow: {workflow}') - images = await asyncio.to_thread(get_images, ws, workflow, client_id, base_url, api_key) except Exception as e: - log.exception(f'Error while receiving images: {e}') - images = None - - ws.close() + log.exception(f'Error during image generation: {e}') + return None return images @@ -209,64 +231,26 @@ class ComfyUIEditImageForm(BaseModel): async def comfyui_edit_image(model: str, payload: ComfyUIEditImageForm, client_id, base_url, api_key): ws_url = base_url.replace('http://', 'ws://').replace('https://', 'wss://') workflow = json.loads(payload.workflow.workflow) + _apply_workflow_nodes(workflow, payload.workflow.nodes, model, payload) - for node in payload.workflow.nodes: - if node.type: - if node.type == 'model': - for node_id in node.node_ids: - workflow[node_id]['inputs'][node.key] = model - elif node.type == 'image': - if isinstance(payload.image, list): - # check if multiple images are provided - for idx, node_id in enumerate(node.node_ids): - if idx < len(payload.image): - workflow[node_id]['inputs'][node.key] = payload.image[idx] - else: - for node_id in node.node_ids: - workflow[node_id]['inputs'][node.key] = payload.image - elif node.type == 'prompt': - for node_id in node.node_ids: - workflow[node_id]['inputs'][node.key if node.key else 'text'] = payload.prompt - elif node.type == 'negative_prompt': - for node_id in node.node_ids: - workflow[node_id]['inputs'][node.key if node.key else 'text'] = payload.negative_prompt - elif node.type == 'width': - for node_id in node.node_ids: - workflow[node_id]['inputs'][node.key if node.key else 'width'] = payload.width - elif node.type == 'height': - for node_id in node.node_ids: - workflow[node_id]['inputs'][node.key if node.key else 'height'] = payload.height - elif node.type == 'n': - for node_id in node.node_ids: - workflow[node_id]['inputs'][node.key if node.key else 'batch_size'] = payload.n - elif node.type == 'steps': - for node_id in node.node_ids: - workflow[node_id]['inputs'][node.key if node.key else 'steps'] = payload.steps - elif node.type == 'seed': - seed = payload.seed if payload.seed else random.randint(0, 1125899906842624) - for node_id in node.node_ids: - workflow[node_id]['inputs'][node.key] = seed - else: - for node_id in node.node_ids: - workflow[node_id]['inputs'][node.key] = node.value + headers = {'Authorization': f'Bearer {api_key}'} + session = await get_session() try: - ws = websocket.WebSocket() - headers = {'Authorization': f'Bearer {api_key}'} - ws.connect(f'{ws_url}/ws?clientId={client_id}', header=headers) - log.info('WebSocket connection established.') - except Exception as e: + async with session.ws_connect( + f'{ws_url}/ws?clientId={client_id}', + headers=headers, + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as ws: + log.info('WebSocket connection established.') + log.info('Sending workflow to WebSocket server.') + log.info(f'Workflow: {workflow}') + images = await _ws_get_images(ws, workflow, client_id, base_url, api_key) + except aiohttp.WSServerHandshakeError as e: log.exception(f'Failed to connect to WebSocket server: {e}') return None - - try: - log.info('Sending workflow to WebSocket server.') - log.info(f'Workflow: {workflow}') - images = await asyncio.to_thread(get_images, ws, workflow, client_id, base_url, api_key) except Exception as e: - log.exception(f'Error while receiving images: {e}') - images = None - - ws.close() + log.exception(f'Error during image editing: {e}') + return None return images diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 0d330ff31f..8d3b6dd267 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -401,12 +401,65 @@ def is_opening_code_block(content): return len(backtick_segments) > 1 and len(backtick_segments) % 2 == 0 +_OPENAI_TOOL_DISPLAY_NAMES = { + 'web_search_call': 'Web Search', + 'file_search_call': 'File Search', + 'computer_call': 'Computer Use', +} + + +def _render_openai_tool_call_handler(item: dict, done: bool) -> str: + """Render an OpenAI Responses API server-side tool item as a
block. + + Handles web_search_call, file_search_call, and computer_call items whose + schemas are defined in the openai-python SDK (generated from OpenAPI spec). + """ + item_type = item.get('type', '') + call_id = item.get('id', '') + display_name = _OPENAI_TOOL_DISPLAY_NAMES.get(item_type, item_type) + + # Build a short summary of what the tool did + summary = '' + if item_type == 'web_search_call': + action = item.get('action', {}) + if isinstance(action, dict): + atype = action.get('type', '') + if atype == 'search': + queries = action.get('queries') or [] + query = action.get('query', '') + summary = ( + f'Search: {", ".join(str(q) for q in queries)}' + if queries + else (f'Search: {query}' if query else '') + ) + elif atype == 'open_page': + summary = f'Open page: {action.get("url", "")}' if action.get('url') else '' + elif atype == 'find_in_page': + summary = f'Find in page: {action.get("pattern", "")}' if action.get('pattern') else '' + elif item_type == 'file_search_call': + queries = item.get('queries', []) + if queries: + summary = f'Queries: {", ".join(str(q) for q in queries)}' + elif item_type == 'computer_call': + action = item.get('action') + actions = item.get('actions') + if isinstance(action, dict): + summary = f'Action: {action.get("type", "unknown")}' + elif isinstance(actions, list) and actions: + summary = f'Actions: {", ".join(a.get("type", "?") for a in actions if isinstance(a, dict))}' + + escaped_name = html.escape(display_name) + if done: + return f'
\nTool Executed\n{html.escape(summary)}\n
\n' + return f'
\nExecuting...\n
\n' + + def serialize_output(output: list) -> str: """ Convert OR-aligned output items to HTML for display. For LLM consumption, use convert_output_to_messages() instead. """ - content = '' + parts: list[str] = [] # First pass: collect function_call_output items by call_id for lookup tool_outputs = {} @@ -423,46 +476,52 @@ def serialize_output(output: list) -> str: if 'text' in content_part: text = content_part.get('text', '').strip() if text: - content = f'{content}{text}\n' + parts.append(text) elif item_type == 'function_call': - # Render tool call inline with its result (if available) - if content and not content.endswith('\n'): - content += '\n' - call_id = item.get('call_id', '') name = item.get('name', '') arguments = item.get('arguments', '') result_item = tool_outputs.get(call_id) if result_item: - result_text = '' + result_parts: list[str] = [] for result_output in result_item.get('output', []): if 'text' in result_output: output_text = result_output.get('text', '') - result_text += str(output_text) if not isinstance(output_text, str) else output_text + result_parts.append(str(output_text) if not isinstance(output_text, str) else output_text) + result_text = ''.join(result_parts) files = result_item.get('files') embeds = result_item.get('embeds', '') - content += f'
\nTool Executed\n{html.escape(json.dumps(result_text, ensure_ascii=False))}\n
\n' + parts.append( + f'
\nTool Executed\n{html.escape(json.dumps(result_text, ensure_ascii=False))}\n
' + ) else: - content += f'
\nExecuting...\n
\n' + parts.append( + f'
\nExecuting...\n
' + ) elif item_type == 'function_call_output': # Already handled inline with function_call above pass + elif item_type in _OPENAI_TOOL_DISPLAY_NAMES: + status = item.get('status', 'in_progress') + done = status in ('completed', 'failed', 'incomplete') or idx != len(output) - 1 + parts.append(_render_openai_tool_call_handler(item, done).rstrip('\n')) + elif item_type == 'reasoning': - reasoning_content = '' + reasoning_parts: list[str] = [] # Check for 'summary' (new structure) or 'content' (legacy/fallback) source_list = item.get('summary', []) or item.get('content', []) for content_part in source_list: if 'text' in content_part: - reasoning_content += content_part.get('text', '') + reasoning_parts.append(content_part.get('text', '')) elif 'summary' in content_part: # Handle potential nested logic if any pass - reasoning_content = reasoning_content.strip() + reasoning_content = ''.join(reasoning_parts).strip() duration = item.get('duration') status = item.get('status', 'in_progress') @@ -471,9 +530,6 @@ def serialize_output(output: list) -> str: # render as done (a subsequent item means reasoning is complete) is_last_item = idx == len(output) - 1 - if content and not content.endswith('\n'): - content += '\n' - display = html.escape( '\n'.join( (f'> {line}' if not line.startswith('>') else line) for line in reasoning_content.splitlines() @@ -481,19 +537,26 @@ def serialize_output(output: list) -> str: ) if status == 'completed' or duration is not None or not is_last_item: - content = f'{content}
\nThought for {duration or 0} seconds\n{display}\n
\n' + parts.append( + f'
\nThought for {duration or 0} seconds\n{display}\n
' + ) else: - content = f'{content}
\nThinking…\n{display}\n
\n' + parts.append( + f'
\nThinking…\n{display}\n
' + ) elif item_type == 'open_webui:code_interpreter': + # Code interpreter needs to inspect/mutate prior accumulated content + # to strip trailing unclosed code fences — materialize only here. + content = '\n'.join(parts) content_stripped, original_whitespace = split_content_and_whitespace(content) if is_opening_code_block(content_stripped): content = content_stripped.rstrip('`').rstrip() + original_whitespace else: content = content_stripped + original_whitespace - if content and not content.endswith('\n'): - content += '\n' + # Re-split back into parts list after mutation + parts = [content] if content else [] # Render the code_interpreter item as a
block # so the frontend Collapsible renders "Analyzing..."/"Analyzed". @@ -519,11 +582,15 @@ def serialize_output(output: list) -> str: output_attr = f' output="{html.escape(output_json)}"' if status == 'completed' or duration is not None or not is_last_item: - content += f'
\nAnalyzed\n{display}\n
\n' + parts.append( + f'
\nAnalyzed\n{display}\n
' + ) else: - content += f'
\nAnalyzing…\n{display}\n
\n' + parts.append( + f'
\nAnalyzing…\n{display}\n
' + ) - return content.strip() + return '\n'.join(parts).strip() def deep_merge(target, source): @@ -2392,6 +2459,7 @@ async def process_chat_payload(request, form_data, user, metadata, model): tool_ids = form_data.pop('tool_ids', None) terminal_id = form_data.pop('terminal_id', None) files = form_data.pop('files', None) + form_data.pop('folder_id', None) # Caller-provided OpenAI-style tools take precedence over server-side # tool resolution (tool_ids, MCP servers, builtin tools). @@ -2460,6 +2528,7 @@ async def process_chat_payload(request, form_data, user, metadata, model): metadata = { **metadata, + 'model_id': form_data.get('model'), 'tool_ids': tool_ids, 'terminal_id': terminal_id, 'files': files, @@ -2618,7 +2687,8 @@ async def process_chat_payload(request, form_data, user, metadata, model): # Resolve terminal tools if terminal_id is set (outside tool_ids check # so system terminals work even when no other tools are selected) - if terminal_id: + terminal_capability = (model.get('info', {}).get('meta', {}).get('capabilities') or {}).get('terminal', True) + if terminal_id and terminal_capability: try: terminal_result = await get_terminal_tools( request, @@ -2846,13 +2916,32 @@ def build_response_object(response, response_data): async def get_system_oauth_token(request, user): + """Get the system OAuth token for a user. + + Primary path: use the oauth_session_id cookie (browser requests). + Fallback: look up the user's most recent OAuth session from the DB + (covers automations, API calls, and other cookie-less contexts). + """ oauth_token = None try: - if request.cookies.get('oauth_session_id', None): + oauth_session_id = request.cookies.get('oauth_session_id', None) + if oauth_session_id: oauth_token = await request.app.state.oauth_manager.get_oauth_token( user.id, - request.cookies.get('oauth_session_id', None), + oauth_session_id, ) + + # Fallback: no cookie (automation, API key, etc.) — use most recent session + if oauth_token is None: + from open_webui.models.oauth_sessions import OAuthSessions + + sessions = await OAuthSessions.get_sessions_by_user_id(user.id) + if sessions: + best = max(sessions, key=lambda s: s.updated_at) + oauth_token = await request.app.state.oauth_manager.get_oauth_token( + user.id, + best.id, + ) except Exception as e: log.error(f'Error getting OAuth token: {e}') return oauth_token @@ -3067,6 +3156,10 @@ async def outlet_filter_handler(ctx): Replaces the separate POST /api/chat/completed round-trip. Persists outlet-modified content to DB and emits a chat:outlet event so the frontend can sync its in-memory state. + + For temp chats (local: prefix), messages are built from form_data + plus the assistant response message stored in ctx['assistant_message'], + since temp chats have no DB-persisted history. """ request = ctx['request'] user = ctx['user'] @@ -3078,17 +3171,45 @@ async def outlet_filter_handler(ctx): chat_id = metadata.get('chat_id', '') message_id = metadata.get('message_id') - if not chat_id or chat_id.startswith('local:') or not message_id: + if not chat_id or not message_id: return - try: - messages_map = await Chats.get_messages_map_by_chat_id(chat_id) - if not messages_map: - return + is_temp_chat = chat_id.startswith('local:') - message_list = get_message_list(messages_map, message_id) - if not message_list: - return + try: + messages_map = None + + if is_temp_chat: + # Temp chats have no DB record — build message list from + # the in-memory form_data plus the assistant response. + form_messages = ctx.get('form_data', {}).get('messages', []) + assistant_message = ctx.get('assistant_message', {}) + + message_list = [ + { + 'role': m.get('role'), + 'content': m.get('content', ''), + } + for m in form_messages + ] + + # Append the full assistant message (content, output, usage, etc.) + if assistant_message: + message_list.append( + { + 'id': message_id, + 'role': 'assistant', + **assistant_message, + } + ) + else: + messages_map = await Chats.get_messages_map_by_chat_id(chat_id) + if not messages_map: + return + + message_list = get_message_list(messages_map, message_id) + if not message_list: + return model_id = model.get('id') if isinstance(model, dict) else model @@ -3101,6 +3222,7 @@ async def outlet_filter_handler(ctx): 'content': m.get('content', ''), 'info': m.get('info'), 'timestamp': m.get('timestamp'), + **({'output': m['output']} if m.get('output') else {}), **({'usage': m['usage']} if m.get('usage') else {}), **({'sources': m['sources']} if m.get('sources') else {}), } @@ -3141,20 +3263,22 @@ async def outlet_filter_handler(ctx): ) # Persist outlet-modified content and notify frontend + # (skip DB persistence for temp chats — they have no DB record) if outlet_result and outlet_result.get('messages'): - for msg in outlet_result['messages']: - msg_id = msg.get('id') - if msg_id and msg_id in messages_map: - original = messages_map[msg_id] - if original.get('content') != msg.get('content'): - await Chats.upsert_message_to_chat_by_id_and_message_id( - chat_id, - msg_id, - { - 'content': msg['content'], - 'originalContent': original.get('content'), - }, - ) + if not is_temp_chat and messages_map: + for message in outlet_result['messages']: + outlet_message_id = message.get('id') + if outlet_message_id and outlet_message_id in messages_map: + original_message = messages_map[outlet_message_id] + if original_message.get('content') != message.get('content'): + await Chats.upsert_message_to_chat_by_id_and_message_id( + chat_id, + outlet_message_id, + { + 'content': message['content'], + 'originalContent': original_message.get('content'), + }, + ) if event_emitter: await event_emitter( @@ -3278,7 +3402,7 @@ async def non_streaming_chat_response_handler(response, ctx): await post_webhook( request.app.state.WEBUI_NAME, webhook_url, - f'{title} - {request.app.state.config.WEBUI_URL}/c/{metadata["chat_id"]}\n\n{content}', + f'{content}\n\n{title} - {request.app.state.config.WEBUI_URL}/c/{metadata["chat_id"]}', { 'action': 'chat', 'message': content, @@ -3288,6 +3412,11 @@ async def non_streaming_chat_response_handler(response, ctx): ) await background_tasks_handler(ctx) + ctx['assistant_message'] = { + 'content': content, + 'output': response_output, + **({'usage': usage} if usage else {}), + } await outlet_filter_handler(ctx) response = build_response_object(response, merge_events_into_response(response_data, events)) @@ -3713,6 +3842,40 @@ async def streaming_chat_response_handler(response, ctx): elif data.get('type', '').startswith('response.'): output, response_metadata = handle_responses_streaming_event(data, output) + # Emit citation sources from finalized output items + # (mirrors Chat Completions annotation handling at delta level) + if data.get('type') == 'response.output_item.done': + item = data.get('item', {}) + if item.get('type') == 'message': + for part in item.get('content', []): + for annotation in part.get('annotations', []): + if annotation.get('type') == 'url_citation': + # Handle both flat (Responses API) and nested (Chat Completions) formats + url_citation = annotation.get('url_citation', annotation) + + url = url_citation.get('url', '') + title = url_citation.get('title', url) + + if url: + await event_emitter( + { + 'type': 'source', + 'data': { + 'source': { + 'name': title, + 'url': url, + }, + 'document': [title], + 'metadata': [ + { + 'source': url, + 'name': title, + } + ], + }, + } + ) + processed_data = { 'output': full_output(), 'content': serialize_output(full_output()), @@ -4783,7 +4946,7 @@ async def streaming_chat_response_handler(response, ctx): await post_webhook( request.app.state.WEBUI_NAME, webhook_url, - f'{title} - {request.app.state.config.WEBUI_URL}/c/{metadata["chat_id"]}\n\n{content}', + f'{content}\n\n{title} - {request.app.state.config.WEBUI_URL}/c/{metadata["chat_id"]}', { 'action': 'chat', 'message': content, @@ -4800,6 +4963,11 @@ async def streaming_chat_response_handler(response, ctx): ) await background_tasks_handler(ctx) + ctx['assistant_message'] = { + 'content': serialize_output(output), + 'output': output, + **({'usage': usage} if usage else {}), + } await outlet_filter_handler(ctx) except asyncio.CancelledError: log.warning('Task was cancelled!') diff --git a/backend/open_webui/utils/misc.py b/backend/open_webui/utils/misc.py index 345165db28..670a94b512 100644 --- a/backend/open_webui/utils/misc.py +++ b/backend/open_webui/utils/misc.py @@ -245,6 +245,12 @@ def convert_output_to_messages(output: list, raw: bool = False) -> list[dict]: start_tag = item.get('start_tag', '') end_tag = item.get('end_tag', '') pending_content.append(f'{start_tag}{reasoning_text}{end_tag}') + # NOTE: Some providers (e.g. Moonshot/Kimi K2.5) require + # reasoning_content as a top-level field on assistant + # messages. This should be handled externally via a + # pipeline filter or connection-level middleware, not + # here — adding it universally breaks strict providers + # (OpenAI, Vertex AI, Azure) that reject unknown fields. # else: skip reasoning blocks for normal LLM messages elif item_type == 'open_webui:code_interpreter': diff --git a/backend/open_webui/utils/models.py b/backend/open_webui/utils/models.py index c8ebc190e5..6b12515ba1 100644 --- a/backend/open_webui/utils/models.py +++ b/backend/open_webui/utils/models.py @@ -22,7 +22,7 @@ from open_webui.utils.plugin import ( load_function_module_by_id, get_function_module_from_cache, ) -from open_webui.utils.access_control import has_access +from open_webui.utils.access_control import has_access, has_base_model_access from open_webui.config import ( @@ -283,11 +283,15 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None) # Pre-warm the function module cache once per unique function ID. # This ensures each function's DB freshness check runs exactly once, # not once per (model × function) pair. - for function_id in all_function_ids: + # Only attempt to load functions that actually exist in the local DB; + # imported/custom model configs may reference tools or filters the user + # hasn't installed, and trying to load those would cause persistent + # "Failed to load function module" log spam on every model refresh. + for function_id in functions_by_id: try: await get_function_module_from_cache(request, function_id) except Exception as e: - log.info(f'Failed to load function module for {function_id}: {e}') + log.debug(f'Failed to load function module for {function_id}: {e}') # Apply global model defaults to all models # Per-model overrides take precedence over global defaults @@ -404,6 +408,10 @@ async def check_model_access(user, model, db=None): ): raise Exception('Model not found') + # Enforce access on chained base models + if not await has_base_model_access(user.id, model_info, db=db): + raise Exception('Model not found') + async def get_filtered_models(models, user, db=None): # Filter out models that the user does not have access to diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index e8527fce4b..47302e7535 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -513,10 +513,12 @@ async def get_oauth_client_info_with_static_credentials( log.error(f'Error parsing OAuth metadata from {url}: {e}') continue - # Determine scope from server metadata if available + # Let the OAuth provider apply its default scopes. + # We intentionally do NOT join all scopes_supported here — that list + # represents every scope the server *can* grant, not what the client + # should request. Requesting all of them is almost always wrong and + # can break providers like Entra ID that require resource-specific scopes. scope = None - if oauth_server_metadata and oauth_server_metadata.scopes_supported: - scope = ' '.join(oauth_server_metadata.scopes_supported) # Determine token_endpoint_auth_method token_endpoint_auth_method = 'client_secret_post' @@ -1920,10 +1922,10 @@ class OAuthManager: users_to_logout.append(user) if not users_to_logout and sid: - log.info(f'Back-channel logout: no user found by sub, sid-based lookup not yet supported (sid={sid})') + log.debug(f'Back-channel logout: no user found by sub, sid-based lookup not yet supported (sid={sid})') if not users_to_logout: - log.info(f'Back-channel logout: no matching user for provider={matched_provider}, sub={sub}, sid={sid}') + log.debug(f'Back-channel logout: no matching user for provider={matched_provider}, sub={sub}, sid={sid}') return JSONResponse(status_code=200, content={}) # 9. Revoke tokens and delete sessions diff --git a/backend/open_webui/utils/security_headers.py b/backend/open_webui/utils/security_headers.py index 33956688a1..ecc3b6eb30 100644 --- a/backend/open_webui/utils/security_headers.py +++ b/backend/open_webui/utils/security_headers.py @@ -28,6 +28,10 @@ def set_security_headers() -> Dict[str, str]: - x-frame-options - x-permitted-cross-domain-policies - content-security-policy + - content-security-policy-report-only + - cross-origin-embedder-policy + - cross-origin-opener-policy + - cross-origin-resource-policy - reporting-endpoints Each environment variable is associated with a specific setter function @@ -48,6 +52,10 @@ def set_security_headers() -> Dict[str, str]: 'XFRAME_OPTIONS': set_xframe, 'XPERMITTED_CROSS_DOMAIN_POLICIES': set_xpermitted_cross_domain_policies, 'CONTENT_SECURITY_POLICY': set_content_security_policy, + 'CONTENT_SECURITY_POLICY_REPORT_ONLY': set_content_security_policy_report_only, + 'CROSS_ORIGIN_EMBEDDER_POLICY': set_cross_origin_embedder_policy, + 'CROSS_ORIGIN_OPENER_POLICY': set_cross_origin_opener_policy, + 'CROSS_ORIGIN_RESOURCE_POLICY': set_cross_origin_resource_policy, 'REPORTING_ENDPOINTS': set_reporting_endpoints, } @@ -135,6 +143,38 @@ def set_content_security_policy(value: str): return {'Content-Security-Policy': value} +# Set Content-Security-Policy-Report-Only response header +def set_content_security_policy_report_only(value: str): + return {'Content-Security-Policy-Report-Only': value} + + +# Set Cross-Origin-Embedder-Policy response header +def set_cross_origin_embedder_policy(value: str): + pattern = r'^(unsafe-none|require-corp|credentialless)$' + match = re.match(pattern, value, re.IGNORECASE) + if not match: + value = 'require-corp' + return {'Cross-Origin-Embedder-Policy': value} + + +# Set Cross-Origin-Opener-Policy response header +def set_cross_origin_opener_policy(value: str): + pattern = r'^(unsafe-none|same-origin-allow-popups|same-origin)$' + match = re.match(pattern, value, re.IGNORECASE) + if not match: + value = 'same-origin' + return {'Cross-Origin-Opener-Policy': value} + + +# Set Cross-Origin-Resource-Policy response header +def set_cross_origin_resource_policy(value: str): + pattern = r'^(same-site|same-origin|cross-origin)$' + match = re.match(pattern, value, re.IGNORECASE) + if not match: + value = 'same-origin' + return {'Cross-Origin-Resource-Policy': value} + + # Set Reporting-Endpoints response header def set_reporting_endpoints(value: str): return {'Reporting-Endpoints': value} diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index da817c4741..9f3ab0bce4 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -44,6 +44,7 @@ from open_webui.utils.plugin import load_tool_module_by_id from open_webui.utils.access_control import has_access, has_connection_access from open_webui.config import BYPASS_ADMIN_ACCESS_CONTROL from open_webui.env import ( + AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT, AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER, AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA, @@ -93,6 +94,10 @@ from open_webui.tools.builtin import ( list_automations, toggle_automation, delete_automation, + search_calendar_events, + create_calendar_event, + update_calendar_event, + delete_calendar_event, ) import copy @@ -547,11 +552,25 @@ async def get_builtin_tools( builtin_functions.extend([create_tasks, update_task]) # Automation tools - create and manage scheduled automations from chat - if is_builtin_tool_enabled('automations') and await has_user_permission('automations'): + if ( + is_builtin_tool_enabled('automations') + and getattr(request.app.state.config, 'ENABLE_AUTOMATIONS', False) + and await has_user_permission('automations') + ): builtin_functions.extend( [create_automation, update_automation, list_automations, toggle_automation, delete_automation] ) + # Calendar tools - search/create/update/delete events + if ( + is_builtin_tool_enabled('calendar') + and getattr(request.app.state.config, 'ENABLE_CALENDAR', False) + and await has_user_permission('calendar') + ): + builtin_functions.extend( + [search_calendar_events, create_calendar_event, update_calendar_event, delete_calendar_event] + ) + for func in builtin_functions: callable = await get_async_tool_function_and_apply_extra_params( func, @@ -889,7 +908,9 @@ async def get_terminal_cwd( timeout=aiohttp.ClientTimeout(total=5), trust_env=True, ) as session: - async with session.get(cwd_url, headers=headers, cookies=cookies or {}) as resp: + async with session.get( + cwd_url, headers=headers, cookies=cookies or {}, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.status == 200: data = await resp.json() return data.get('cwd') @@ -916,7 +937,7 @@ async def get_terminal_system_prompt( trust_env=True, ) as session: # 1. Check feature flag - async with session.get(f'{base}/api/config') as resp: + async with session.get(f'{base}/api/config', ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: if resp.status != 200: return None config = await resp.json() @@ -924,7 +945,9 @@ async def get_terminal_system_prompt( return None # 2. Fetch system prompt - async with session.get(f'{base}/system', headers=headers, cookies=cookies or {}) as resp: + async with session.get( + f'{base}/system', headers=headers, cookies=cookies or {}, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.status == 200: data = await resp.json() return data.get('prompt') diff --git a/backend/open_webui/utils/webhook.py b/backend/open_webui/utils/webhook.py index 11c94675d1..ee7f3ab3b2 100644 --- a/backend/open_webui/utils/webhook.py +++ b/backend/open_webui/utils/webhook.py @@ -3,7 +3,7 @@ import logging import aiohttp from open_webui.config import WEBUI_FAVICON_URL -from open_webui.env import AIOHTTP_CLIENT_TIMEOUT, VERSION +from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT, VERSION log = logging.getLogger(__name__) @@ -53,7 +53,7 @@ async def post_webhook(name: str, url: str, message: str, event_data: dict) -> b async with aiohttp.ClientSession( trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) ) as session: - async with session.post(url, json=payload) as r: + async with session.post(url, json=payload, ssl=AIOHTTP_CLIENT_SESSION_SSL) as r: r_text = await r.text() r.raise_for_status() log.debug(f'r.text: {r_text}') diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md deleted file mode 100644 index 5b37c8f8c8..0000000000 --- a/docs/CONTRIBUTING.md +++ /dev/null @@ -1,88 +0,0 @@ -# Contributing to Open WebUI - -🚀 **Welcome, Contributors!** 🚀 - -Your interest in contributing to Open WebUI is greatly appreciated. This document is here to guide you through the process, ensuring your contributions enhance the project effectively. Let's make Open WebUI even better, together! - -## 📌 Key Points - -### 🦙 Ollama vs. Open WebUI - -It's crucial to distinguish between Ollama and Open WebUI: - -- **Open WebUI** focuses on providing an intuitive and responsive web interface for chat interactions. -- **Ollama** is the underlying technology that powers these interactions. - -If your issue or contribution pertains directly to the core Ollama technology, please direct it to the appropriate [Ollama project repository](https://ollama.com/). Open WebUI's repository is dedicated to the web interface aspect only. - -### 🚨 Reporting Issues - -Noticed something off? Have an idea? Check our [Issues tab](https://github.com/open-webui/open-webui/issues) to see if it's already been reported or suggested. If not, feel free to open a new issue. When reporting an issue, please follow our issue templates. These templates are designed to ensure that all necessary details are provided from the start, enabling us to address your concerns more efficiently. - -> [!IMPORTANT] -> -> - **Template Compliance:** Please be aware that failure to follow the provided issue template, or not providing the requested information at all, will likely result in your issue being closed without further consideration. This approach is critical for maintaining the manageability and integrity of issue tracking. -> - **Detail is Key:** To ensure your issue is understood and can be effectively addressed, it's imperative to include comprehensive details. Descriptions should be clear, including steps to reproduce, expected outcomes, and actual results. Lack of sufficient detail may hinder our ability to resolve your issue. - -> [!WARNING] -> Reporting vulnerabilities is not wanted through Issues! -> Instead, [use the security reporting functionality](https://github.com/open-webui/open-webui/security) and ensure you comply with the outlined requirements. - -### 🧭 Scope of Support - -We've noticed an uptick in issues not directly related to Open WebUI but rather to the environment it's run in, especially Docker setups. While we strive to support Docker deployment, understanding Docker fundamentals is crucial for a smooth experience. - -- **Docker Deployment Support**: Open WebUI supports Docker deployment. Familiarity with Docker is assumed. For Docker basics, please refer to the [official Docker documentation](https://docs.docker.com/get-started/overview/). - -- **Advanced Configurations**: Setting up reverse proxies for HTTPS and managing Docker deployments requires foundational knowledge. There are numerous online resources available to learn these skills. Ensuring you have this knowledge will greatly enhance your experience with Open WebUI and similar projects. - -- **Check the documentation and help improve it**: [Our documentation](https://docs.openwebui.com) has ever growing troubleshooting guides and detailed installation tutorials. Please verify if it is of help to your issue and help expand it by submitting issues and PRs on our [Docs Repository](https://github.com/open-webui/docs). - -## 💡 Contributing - -Looking to contribute? Great! Here's how you can help: - -### 🛠 Pull Requests - -We welcome pull requests. Before submitting one, please: - -1. Open a discussion regarding your ideas [here](https://github.com/open-webui/open-webui/discussions/new/choose). -2. Follow the project's coding standards and include tests for new features. -3. Update documentation as necessary. -4. Write clear, descriptive commit messages. -5. It's essential to complete your pull request in a timely manner. We move fast, and having PRs hang around too long is not feasible. If you can't get it done within a reasonable time frame, we may have to close it to keep the project moving forward. - -> [!NOTE] -> The Pull Request Template has various requirements outlined. Go through the PR-checklist one by one and ensure you completed all steps before submitting your PR for review (you can open it as draft otherwise!). - -### 📚 Documentation & Tutorials - -Help us make Open WebUI more accessible by improving the documentation, writing tutorials, or creating guides on setting up and optimizing the Web UI. - -Help expand our documentation by submitting issues and PRs on our [Docs Repository](https://github.com/open-webui/docs). -We welcome tutorials, guides and other documentation improvements! - -### 🌐 Translations and Internationalization - -Help us make Open WebUI available to a wider audience. In this section, we'll guide you through the process of adding new translations to the project. - -We use JSON files to store translations. You can find the existing translation files in the `src/lib/i18n/locales` directory. Each directory corresponds to a specific language, for example, `en-US` for English (US), `fr-FR` for French (France) and so on. You can refer to [ISO 639 Language Codes](http://www.lingoes.net/en/translator/langcode.htm) to find the appropriate code for a specific language. - -To add a new language: - -- Create a new directory in the `src/lib/i18n/locales` path with the appropriate language code as its name. For instance, if you're adding translations for Spanish (Spain), create a new directory named `es-ES`. -- Copy the American English translation file(s) (from `en-US` directory in `src/lib/i18n/locale`) to this new directory and update the string values in JSON format according to your language. Make sure to preserve the structure of the JSON object. -- Add the language code and its respective title to languages file at `src/lib/i18n/locales/languages.json`. - -> [!NOTE] -> When adding new translations, do so in a standalone PR! Feature PRs or PRs fixing a bug should not contain translation updates. Always keep the scope of a PR narrow. - -### 🤔 Questions & Feedback - -Got questions or feedback? Join our [Discord community](https://discord.gg/5rJgQTnV4s) or open an issue or discussion. We're here to help! - -## 🙏 Thank You! - -Your contributions, big or small, make a significant impact on Open WebUI. We're excited to see what you bring to the project! - -Together, let's create an even more powerful tool for the community. 🌟 diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 4113c35a78..0000000000 --- a/docs/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Project workflow - -[![](https://mermaid.ink/img/pako:eNq1k01rAjEQhv_KkFNLFe1N9iAUevFSRVl6Cci4Gd1ANtlmsmtF_O_N7iqtHxR76ClhMu87zwyZvcicIpEIpo-KbEavGjceC2lL9EFnukQbIGXygNye5y9TY7DAZTpZLsjXXVYXg3dapRM4hh9mu5A7-3hTfSXtAtJK21Tsj8dPl3USmJZkGVbebWNKD2rNOjAYl6HJHYdkNBwNpb3U9aNZvzFNYE6h8tFiSyZzBUGJG4K1dwVwTSYQrCptlLRvLt5dA5i2la5Ruk51Ux0VKQjuxPVbAwuyiuFlNgHfzJ5DoxtgqQf1813gnZRLZ5lAYcD7WT1lpGtiQKug9C4jZrrp-Fd-1-Y1bdzo4dvnZDLz7lPHyj8sOgfg4x84E7RTuEaZt8yRZqtDfgT_rwG2u3Dv_ERPFOQL1Cqu2F5aAClCTgVJkcSrojVWJkgh7SGmYhXcYmczkQRfUU9UZfQ4baRI1miYDl_QqlPg?type=png)](https://mermaid.live/edit#pako:eNq1k01rAjEQhv_KkFNLFe1N9iAUevFSRVl6Cci4Gd1ANtlmsmtF_O_N7iqtHxR76ClhMu87zwyZvcicIpEIpo-KbEavGjceC2lL9EFnukQbIGXygNye5y9TY7DAZTpZLsjXXVYXg3dapRM4hh9mu5A7-3hTfSXtAtJK21Tsj8dPl3USmJZkGVbebWNKD2rNOjAYl6HJHYdkNBwNpb3U9aNZvzFNYE6h8tFiSyZzBUGJG4K1dwVwTSYQrCptlLRvLt5dA5i2la5Ruk51Ux0VKQjuxPVbAwuyiuFlNgHfzJ5DoxtgqQf1813gnZRLZ5lAYcD7WT1lpGtiQKug9C4jZrrp-Fd-1-Y1bdzo4dvnZDLz7lPHyj8sOgfg4x84E7RTuEaZt8yRZqtDfgT_rwG2u3Dv_ERPFOQL1Cqu2F5aAClCTgVJkcSrojVWJkgh7SGmYhXcYmczkQRfUU9UZfQ4baRI1miYDl_QqlPg) diff --git a/docs/apache.md b/docs/apache.md deleted file mode 100644 index bdf119b5b6..0000000000 --- a/docs/apache.md +++ /dev/null @@ -1,205 +0,0 @@ -# Hosting UI and Models separately - -Sometimes, it's beneficial to host Ollama, separate from the UI, but retain the RAG and RBAC support features shared across users: - -# Open WebUI Configuration - -## UI Configuration - -For the UI configuration, you can set up the Apache VirtualHost as follows: - -``` -# Assuming you have a website hosting this UI at "server.com" - - ServerName server.com - DocumentRoot /home/server/public_html - - ProxyPass / http://server.com:3000/ nocanon - ProxyPassReverse / http://server.com:3000/ - # Needed after 0.5 - ProxyPass / ws://server.com:3000/ nocanon - ProxyPassReverse / ws://server.com:3000/ - - -``` - -Enable the site first before you can request SSL: - -`a2ensite server.com.conf` # this will enable the site. a2ensite is short for "Apache 2 Enable Site" - -``` -# For SSL - - ServerName server.com - DocumentRoot /home/server/public_html - - ProxyPass / http://server.com:3000/ nocanon - ProxyPassReverse / http://server.com:3000/ - # Needed after 0.5 - ProxyPass / ws://server.com:3000/ nocanon - ProxyPassReverse / ws://server.com:3000/ - - SSLEngine on - SSLCertificateFile /etc/ssl/virtualmin/170514456861234/ssl.cert - SSLCertificateKeyFile /etc/ssl/virtualmin/170514456861234/ssl.key - SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 - - SSLProxyEngine on - SSLCACertificateFile /etc/ssl/virtualmin/170514456865864/ssl.ca - - -``` - -I'm using virtualmin here for my SSL clusters, but you can also use certbot directly or your preferred SSL method. To use SSL: - -### Prerequisites. - -Run the following commands: - -`snap install certbot --classic` -`snap apt install python3-certbot-apache` (this will install the apache plugin). - -Navigate to the apache sites-available directory: - -`cd /etc/apache2/sites-available/` - -Create server.com.conf if it is not yet already created, containing the above `` configuration (it should match your case. Modify as necessary). Use the one without the SSL: - -Once it's created, run `certbot --apache -d server.com`, this will request and add/create an SSL keys for you as well as create the server.com.le-ssl.conf - -# Configuring Ollama Server - -On your latest installation of Ollama, make sure that you have setup your api server from the official Ollama reference: - -[Ollama FAQ](https://github.com/jmorganca/ollama/blob/main/docs/faq.md) - -### TL;DR - -The guide doesn't seem to match the current updated service file on linux. So, we will address it here: - -Unless when you're compiling Ollama from source, installing with the standard install `curl https://ollama.com/install.sh | sh` creates a file called `ollama.service` in /etc/systemd/system. You can use nano to edit the file: - -``` -sudo nano /etc/systemd/system/ollama.service -``` - -Add the following lines: - -``` -Environment="OLLAMA_HOST=0.0.0.0:11434" # this line is mandatory. You can also specify -``` - -For instance: - -``` -[Unit] -Description=Ollama Service -After=network-online.target - -[Service] -ExecStart=/usr/local/bin/ollama serve -Environment="OLLAMA_HOST=0.0.0.0:11434" # this line is mandatory. You can also specify 192.168.254.109:DIFFERENT_PORT, format -Environment="OLLAMA_ORIGINS=http://192.168.254.106:11434,https://models.server.city" # this line is optional -User=ollama -Group=ollama -Restart=always -RestartSec=3 -Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/s> - -[Install] -WantedBy=default.target -``` - -Save the file by pressing CTRL+S, then press CTRL+X - -When your computer restarts, the Ollama server will now be listening on the IP:PORT you specified, in this case 0.0.0.0:11434, or 192.168.254.106:11434 (whatever your local IP address is). Make sure that your router is correctly configured to serve pages from that local IP by forwarding 11434 to your local IP server. - -# Ollama Model Configuration - -## For the Ollama model configuration, use the following Apache VirtualHost setup: - -Navigate to the apache sites-available directory: - -`cd /etc/apache2/sites-available/` - -`nano models.server.city.conf` # match this with your ollama server domain - -Add the following virtualhost containing this example (modify as needed): - -``` - -# Assuming you have a website hosting this UI at "models.server.city" - - - DocumentRoot "/var/www/html/" - ServerName models.server.city - - Options None - Require all granted - - - ProxyRequests Off - ProxyPreserveHost On - ProxyAddHeaders On - SSLProxyEngine on - - ProxyPass / http://server.city:1000/ nocanon # or port 11434 - ProxyPassReverse / http://server.city:1000/ # or port 11434 - - SSLCertificateFile /etc/letsencrypt/live/models.server.city/fullchain.pem - SSLCertificateKeyFile /etc/letsencrypt/live/models.server.city/privkey.pem - Include /etc/letsencrypt/options-ssl-apache.conf - - -``` - -You may need to enable the site first (if you haven't done so yet) before you can request SSL: - -`a2ensite models.server.city.conf` - -#### For the SSL part of Ollama server - -Run the following commands: - -Navigate to the apache sites-available directory: - -`cd /etc/apache2/sites-available/` -`certbot --apache -d server.com` - -``` - - DocumentRoot "/var/www/html/" - ServerName models.server.city - - Options None - Require all granted - - - ProxyRequests Off - ProxyPreserveHost On - ProxyAddHeaders On - SSLProxyEngine on - - ProxyPass / http://server.city:1000/ nocanon # or port 11434 - ProxyPassReverse / http://server.city:1000/ # or port 11434 - - RewriteEngine on - RewriteCond %{SERVER_NAME} =models.server.city - RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] - - -``` - -Don't forget to restart/reload Apache with `systemctl reload apache2` - -Open your site at https://server.com! - -**Congratulations**, your _**Open-AI-like Chat-GPT style UI**_ is now serving AI with RAG, RBAC and multimodal features! Download Ollama models if you haven't yet done so! - -If you encounter any misconfiguration or errors, please file an issue or engage with our discussion. There are a lot of friendly developers here to assist you. - -Let's make this UI much more user friendly for everyone! - -Thanks for making open-webui your UI Choice for AI! - -This doc is made by **Bob Reyes**, your **Open-WebUI** fan from the Philippines. diff --git a/package-lock.json b/package-lock.json index 538792470e..e3175ba8a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "open-webui", - "version": "0.8.12", + "version": "0.9.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "open-webui", - "version": "0.8.12", + "version": "0.9.1", "dependencies": { "@azure/msal-browser": "^4.5.0", "@codemirror/lang-javascript": "^6.2.2", @@ -54,6 +54,7 @@ "dayjs": "^1.11.10", "dompurify": "^3.2.6", "eventsource-parser": "^1.1.2", + "fast-deep-equal": "^3.1.3", "file-saver": "^2.0.5", "focus-trap": "^7.6.4", "fuse.js": "^7.0.0", @@ -214,42 +215,40 @@ "license": "(Apache-2.0 AND BSD-3-Clause)" }, "node_modules/@chevrotain/cst-dts-gen": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.2.tgz", - "integrity": "sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-12.0.0.tgz", + "integrity": "sha512-fSL4KXjTl7cDgf0B5Rip9Q05BOrYvkJV/RrBTE/bKDN096E4hN/ySpcBK5B24T76dlQ2i32Zc3PAE27jFnFrKg==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/gast": "11.1.2", - "@chevrotain/types": "11.1.2", - "lodash-es": "4.17.23" + "@chevrotain/gast": "12.0.0", + "@chevrotain/types": "12.0.0" } }, "node_modules/@chevrotain/gast": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.2.tgz", - "integrity": "sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-12.0.0.tgz", + "integrity": "sha512-1ne/m3XsIT8aEdrvT33so0GUC+wkctpUPK6zU9IlOyJLUbR0rg4G7ZiApiJbggpgPir9ERy3FRjT6T7lpgetnQ==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/types": "11.1.2", - "lodash-es": "4.17.23" + "@chevrotain/types": "12.0.0" } }, "node_modules/@chevrotain/regexp-to-ast": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.2.tgz", - "integrity": "sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-12.0.0.tgz", + "integrity": "sha512-p+EW9MaJwgaHguhoqwOtx/FwuGr+DnNn857sXWOi/mClXIkPGl3rn7hGNWvo31HA3vyeQxjqe+H36yZJwYU8cA==", "license": "Apache-2.0" }, "node_modules/@chevrotain/types": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", - "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-12.0.0.tgz", + "integrity": "sha512-S+04vjFQKeuYw0/eW3U52LkAHQsB1ASxsPGsLPUyQgrZ2iNNibQrsidruDzjEX2JYfespXMG0eZmXlhA6z7nWA==", "license": "Apache-2.0" }, "node_modules/@chevrotain/utils": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.2.tgz", - "integrity": "sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-12.0.0.tgz", + "integrity": "sha512-lB59uJoaGIfOOL9knQqQRfhl9g7x8/wqFkp13zTdkRu1huG9kg6IJs1O8hqj9rs6h7orGxHJUKb+mX3rPbWGhA==", "license": "Apache-2.0" }, "node_modules/@codemirror/autocomplete": { @@ -1247,9 +1246,9 @@ "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -1373,9 +1372,9 @@ "license": "MIT" }, "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -3583,9 +3582,9 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.55.0", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.55.0.tgz", - "integrity": "sha512-MdFRjevVxmAknf2NbaUkDF16jSIzXMWd4Nfah0Qp8TtQVoSp3bV4jKt8mX7z7qTUTWvgSaxtR0EG5WJf53gcuA==", + "version": "2.57.1", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.57.1.tgz", + "integrity": "sha512-VRdSbB96cI1EnRh09CqmnQqP/YJvET5buj8S6k7CxaJqBJD4bw4fRKDjcarAj/eX9k2eHifQfDH8NtOh+ZxxPw==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -3611,7 +3610,7 @@ "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", - "typescript": "^5.3.3", + "typescript": "^5.3.3 || ^6.0.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" }, "peerDependenciesMeta": { @@ -5389,9 +5388,9 @@ "license": "MIT" }, "node_modules/@xmldom/xmldom": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", - "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", + "version": "0.8.12", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.12.tgz", + "integrity": "sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -5619,9 +5618,9 @@ } }, "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -5963,9 +5962,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6368,29 +6367,31 @@ } }, "node_modules/chevrotain": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.2.tgz", - "integrity": "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-12.0.0.tgz", + "integrity": "sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/cst-dts-gen": "11.1.2", - "@chevrotain/gast": "11.1.2", - "@chevrotain/regexp-to-ast": "11.1.2", - "@chevrotain/types": "11.1.2", - "@chevrotain/utils": "11.1.2", - "lodash-es": "4.17.23" + "@chevrotain/cst-dts-gen": "12.0.0", + "@chevrotain/gast": "12.0.0", + "@chevrotain/regexp-to-ast": "12.0.0", + "@chevrotain/types": "12.0.0", + "@chevrotain/utils": "12.0.0" + }, + "engines": { + "node": ">=22.0.0" } }, "node_modules/chevrotain-allstar": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", - "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.4.1.tgz", + "integrity": "sha512-PvVJm3oGqrveUVW2Vt/eZGeiAIsJszYweUcYwcskg9e+IubNYKKD+rHHem7A6XVO22eDAL+inxNIGAzZ/VIWlA==", "license": "MIT", "dependencies": { "lodash-es": "^4.17.21" }, "peerDependencies": { - "chevrotain": "^11.0.0" + "chevrotain": "^12.0.0" } }, "node_modules/chokidar": { @@ -7743,9 +7744,9 @@ } }, "node_modules/dompurify": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz", - "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.0.tgz", + "integrity": "sha512-nolgK9JcaUXMSmW+j1yaSvaEaoXYHwWyGJlkoCTghc97KgGDDSnpoU/PlEnw63Ah+TGKFOyY+X5LnxaWbCSfXg==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -8238,9 +8239,9 @@ "license": "MIT" }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -8462,7 +8463,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-fifo": { @@ -9051,9 +9051,9 @@ "license": "MIT" }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -10152,13 +10152,14 @@ } }, "node_modules/langium": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.1.tgz", - "integrity": "sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.2.tgz", + "integrity": "sha512-JUshTRAfHI4/MF9dH2WupvjSXyn8JBuUEWazB8ZVJUtXutT0doDlAv1XKbZ1Pb5sMexa8FF4CFBc0iiul7gbUQ==", "license": "MIT", "dependencies": { - "chevrotain": "~11.1.1", - "chevrotain-allstar": "~0.3.1", + "@chevrotain/regexp-to-ast": "~12.0.0", + "chevrotain": "~12.0.0", + "chevrotain-allstar": "~0.4.1", "vscode-languageserver": "~9.0.1", "vscode-languageserver-textdocument": "~1.0.11", "vscode-uri": "~3.1.0" @@ -10600,16 +10601,16 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "dev": true, "license": "MIT" }, "node_modules/lodash-es": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", - "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "license": "MIT" }, "node_modules/lodash.merge": { @@ -10870,9 +10871,9 @@ "license": "MIT" }, "node_modules/matcher-collection/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -11103,9 +11104,9 @@ } }, "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -11765,9 +11766,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", "engines": { "node": ">=12" @@ -11914,9 +11915,9 @@ } }, "node_modules/postcss-load-config/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "dev": true, "license": "ISC", "engines": { @@ -12326,9 +12327,9 @@ } }, "node_modules/protobufjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", - "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz", + "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -12460,9 +12461,9 @@ "license": "MIT" }, "node_modules/quick-temp/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -12742,9 +12743,9 @@ "license": "MIT" }, "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -15408,9 +15409,9 @@ } }, "node_modules/vite-plugin-static-copy/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -16152,9 +16153,9 @@ "license": "MIT" }, "node_modules/walk-sync/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -16441,9 +16442,9 @@ } }, "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "license": "ISC", "bin": { "yaml": "bin.mjs" diff --git a/package.json b/package.json index ab0cf78afc..ab246848c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-webui", - "version": "0.8.12", + "version": "0.9.1", "private": true, "scripts": { "dev": "npm run pyodide:fetch && vite dev --host", @@ -98,6 +98,7 @@ "dayjs": "^1.11.10", "dompurify": "^3.2.6", "eventsource-parser": "^1.1.2", + "fast-deep-equal": "^3.1.3", "file-saver": "^2.0.5", "focus-trap": "^7.6.4", "fuse.js": "^7.0.0", diff --git a/pyproject.toml b/pyproject.toml index 27e6faeddf..b6d07a61f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,8 @@ dependencies = [ "python-mimeparse==2.0.0", "sqlalchemy==2.0.48", + "aiosqlite==0.21.0", + "asyncpg==0.30.0", "alembic==1.18.4", "peewee==3.19.0", "peewee-migrate==1.14.3", diff --git a/src/app.css b/src/app.css index 93417b680a..9352177bd8 100644 --- a/src/app.css +++ b/src/app.css @@ -260,6 +260,17 @@ select { display: none; } +/* Hide leaked Mermaid temp containers if render cleanup misses. + Use visibility:hidden (not display:none) so mermaid can still + measure the SVG layout before extracting its HTML. */ +body > div[id^='dmermaid-'], +body > iframe[id^='imermaid-'] { + position: fixed !important; + visibility: hidden !important; + height: 0 !important; + overflow: hidden !important; +} + .scrollbar-hidden:active::-webkit-scrollbar-thumb, .scrollbar-hidden:focus::-webkit-scrollbar-thumb, .scrollbar-hidden:hover::-webkit-scrollbar-thumb { diff --git a/src/lib/apis/calendar/index.ts b/src/lib/apis/calendar/index.ts new file mode 100644 index 0000000000..b3148e6c18 --- /dev/null +++ b/src/lib/apis/calendar/index.ts @@ -0,0 +1,458 @@ +import { WEBUI_API_BASE_URL } from '$lib/constants'; + +export type CalendarModel = { + id: string; + user_id: string; + name: string; + color: string | null; + is_default: boolean; + is_system: boolean; + data: Record | null; + meta: Record | null; + access_grants: any[]; + created_at: number; + updated_at: number; +}; + +export type CalendarEventAttendeeModel = { + id: string; + event_id: string; + user_id: string; + status: string; + meta: Record | null; + created_at: number; + updated_at: number; +}; + +export type CalendarEventModel = { + id: string; + calendar_id: string; + user_id: string; + title: string; + description: string | null; + start_at: number; + end_at: number | null; + all_day: boolean; + rrule: string | null; + color: string | null; + location: string | null; + data: Record | null; + meta: Record | null; + is_cancelled: boolean; + attendees: CalendarEventAttendeeModel[]; + created_at: number; + updated_at: number; + // Set by expand_recurring_event for recurring instances + instance_id?: string; +}; + +export type CalendarEventForm = { + calendar_id: string; + title: string; + description?: string; + start_at: number; + end_at?: number; + all_day?: boolean; + rrule?: string; + color?: string; + location?: string; + data?: Record; + meta?: Record; + attendees?: { user_id: string; status?: string }[]; +}; + +export type CalendarForm = { + name: string; + color?: string; + data?: Record; + meta?: Record; + access_grants?: { target_type: string; target_id: string; permission: string }[]; +}; + +// ── Calendars ───────────────────────────────── + +export const getCalendars = async (token: string): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const createCalendar = async (token: string, form: CalendarForm): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/create`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + }, + body: JSON.stringify(form) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const updateCalendar = async ( + token: string, + calendarId: string, + form: Partial +): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/${calendarId}/update`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + }, + body: JSON.stringify(form) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const deleteCalendar = async (token: string, calendarId: string): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/${calendarId}/delete`, { + method: 'DELETE', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res?.status ?? false; +}; + +export const setDefaultCalendar = async ( + token: string, + calendarId: string +): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/${calendarId}/default`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +// ── Events ───────────────────────────────── + +export const getCalendarEvents = async ( + token: string, + start: string, + end: string, + calendarIds?: string[] +): Promise => { + let error = null; + + const params = new URLSearchParams(); + params.append('start', start); + params.append('end', end); + if (calendarIds && calendarIds.length > 0) { + params.append('calendar_ids', calendarIds.join(',')); + } + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events?${params.toString()}`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const createCalendarEvent = async ( + token: string, + form: CalendarEventForm +): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events/create`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + }, + body: JSON.stringify(form) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const getCalendarEventById = async ( + token: string, + eventId: string +): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events/${eventId}`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const updateCalendarEvent = async ( + token: string, + eventId: string, + form: Partial +): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events/${eventId}/update`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + }, + body: JSON.stringify(form) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const deleteCalendarEvent = async (token: string, eventId: string): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events/${eventId}/delete`, { + method: 'DELETE', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res?.status ?? false; +}; + +export const rsvpCalendarEvent = async ( + token: string, + eventId: string, + status: string +): Promise<{ status: boolean; rsvp: string }> => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events/${eventId}/rsvp`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + }, + body: JSON.stringify({ status }) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const searchCalendarEvents = async ( + token: string, + query: string | null, + skip: number = 0, + limit: number = 30 +): Promise<{ items: CalendarEventModel[]; total: number }> => { + let error = null; + + const params = new URLSearchParams(); + if (query) params.append('query', query); + params.append('skip', skip.toString()); + params.append('limit', limit.toString()); + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/events/search?${params.toString()}`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; diff --git a/src/lib/apis/chats/index.ts b/src/lib/apis/chats/index.ts index e16746707a..028371386c 100644 --- a/src/lib/apis/chats/index.ts +++ b/src/lib/apis/chats/index.ts @@ -953,6 +953,73 @@ export const deleteSharedChatById = async (token: string, id: string) => { return res; }; +export const updateChatAccessGrants = async (token: string, id: string, accessGrants: object[]) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/chats/shared/${id}/access/update`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + ...(token && { authorization: `Bearer ${token}` }) + }, + body: JSON.stringify({ + access_grants: accessGrants + }) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .then((json) => { + return json; + }) + .catch((err) => { + error = err; + + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const getChatAccessGrants = async (token: string, id: string) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/chats/shared/${id}/access`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + ...(token && { authorization: `Bearer ${token}` }) + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .then((json) => { + return json; + }) + .catch((err) => { + error = err; + + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + export const updateChatById = async (token: string, id: string, chat: object) => { let error = null; diff --git a/src/lib/components/admin/Settings/Documents.svelte b/src/lib/components/admin/Settings/Documents.svelte index f8d6193b7d..7fa8dc2e25 100644 --- a/src/lib/components/admin/Settings/Documents.svelte +++ b/src/lib/components/admin/Settings/Documents.svelte @@ -1212,6 +1212,23 @@ {/if} +
+
+ {$i18n.t('Reranking Batch Size')} +
+ +
+ +
+
+
{$i18n.t('Top K')}
diff --git a/src/lib/components/admin/Settings/General.svelte b/src/lib/components/admin/Settings/General.svelte index f2ba4a3ee1..ddb81e844b 100644 --- a/src/lib/components/admin/Settings/General.svelte +++ b/src/lib/components/admin/Settings/General.svelte @@ -740,6 +740,14 @@
{/if} +
+
+ {$i18n.t('Memories')} ({$i18n.t('Beta')}) +
+ + +
+
{$i18n.t('Notes')} ({$i18n.t('Beta')}) @@ -758,10 +766,18 @@
- {$i18n.t('Memories')} ({$i18n.t('Beta')}) + {$i18n.t('Calendar')}
- + +
+ +
+
+ {$i18n.t('Automations')} +
+ +
diff --git a/src/lib/components/admin/Users/Groups/Permissions.svelte b/src/lib/components/admin/Users/Groups/Permissions.svelte index 7bd8fd00e0..cbfcb67b0a 100644 --- a/src/lib/components/admin/Users/Groups/Permissions.svelte +++ b/src/lib/components/admin/Users/Groups/Permissions.svelte @@ -916,6 +916,22 @@
{/if}
+ +
+
+
+ {$i18n.t('Calendar')} +
+ +
+ {#if defaultPermissions?.features?.calendar && !permissions.features.calendar} +
+
+ {$i18n.t('This is a default user permission and will remain enabled.')} +
+
+ {/if} +

diff --git a/src/lib/components/calendar/CalendarEventChip.svelte b/src/lib/components/calendar/CalendarEventChip.svelte new file mode 100644 index 0000000000..b1c3552e6c --- /dev/null +++ b/src/lib/components/calendar/CalendarEventChip.svelte @@ -0,0 +1,32 @@ + + + + + diff --git a/src/lib/components/calendar/CalendarEventModal.svelte b/src/lib/components/calendar/CalendarEventModal.svelte new file mode 100644 index 0000000000..bba3b3426b --- /dev/null +++ b/src/lib/components/calendar/CalendarEventModal.svelte @@ -0,0 +1,295 @@ + + + +
+ +
+ + +
+ + +
+ +
+
{$i18n.t('Calendar')}
+ +
+ + +
+
{$i18n.t('When')}
+
+ + {#if !allDay} + + + + {/if} + +
+
+ + +
+
{$i18n.t('Location')}
+ +
+ + +
+
{$i18n.t('Reminder')}
+ +
+ + +
+
{$i18n.t('Description')}
+ +
+
+ + +
+
+ {#if event && !event.meta?.automation_id} + + {/if} +
+ +
+ + +
+
+
+
+ + diff --git a/src/lib/components/calendar/CalendarSidebar.svelte b/src/lib/components/calendar/CalendarSidebar.svelte new file mode 100644 index 0000000000..d3ea51a472 --- /dev/null +++ b/src/lib/components/calendar/CalendarSidebar.svelte @@ -0,0 +1,233 @@ + + + + +
+ +
+
+
{miniMonthNames[miniMonth]} {miniYear}
+
+ + +
+
+ +
+ {#each ['S', 'M', 'T', 'W', 'T', 'F', 'S'] as d} +
{d}
+ {/each} +
+ +
+ {#each miniDays as day} + + {/each} +
+
+ + +
+
+
+ {$i18n.t('Calendars')} +
+
+ + {#each calendars as cal (cal.id)} +
+ +
+ {/each} +
+
diff --git a/src/lib/components/calendar/CalendarView.svelte b/src/lib/components/calendar/CalendarView.svelte new file mode 100644 index 0000000000..c78de56d8f --- /dev/null +++ b/src/lib/components/calendar/CalendarView.svelte @@ -0,0 +1,323 @@ + + +
+ + {#if view === 'month'} +
+
+ {#each DAY_NAMES as day} +
+ {$i18n.t(day)} +
+ {/each} +
+ +
+ {#each monthDays as day, i} + {@const dayKey = new Date(day.getFullYear(), day.getMonth(), day.getDate()) + .getTime() + .toString()} + {@const dayEvents = eventsByDay[dayKey] || []} + {@const col = i % 7} + {@const row = Math.floor(i / 7)} + + {/each} +
+
+ + + {:else if view === 'week'} +
+
+
+
+
+
+ {#each weekDays as day} +
+
+ {DAY_NAMES[day.getDay()]} +
+
+ {day.getDate()} +
+
+ {/each} +
+ +
+ {#each hours as hour} +
+
+ {hour > 0 ? formatHour(hour) : ''} +
+ {#each weekDays as day} + {@const hourEvents = getEventsForHour(day, hour, filteredEvents)} + + {/each} +
+ {/each} +
+
+
+
+
+ + + {:else} +
+
+ {#each hours as hour} + {@const hourEvents = getEventsForHour(currentDate, hour, filteredEvents)} +
+
+ {formatHour(hour)} +
+ +
+ {/each} +
+
+ {/if} +
diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index a3fd62d3bd..03af994a68 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -13,6 +13,7 @@ import { get, type Unsubscriber, type Writable } from 'svelte/store'; import type { i18n as i18nType } from 'i18next'; import { WEBUI_BASE_URL } from '$lib/constants'; + import equal from 'fast-deep-equal'; import { chatId, @@ -277,7 +278,7 @@ }; let oldSelectedModelIds = ['']; - $: if (JSON.stringify(selectedModelIds) !== JSON.stringify(oldSelectedModelIds)) { + $: if (!equal(selectedModelIds, oldSelectedModelIds)) { onSelectedModelIdsChange(); } @@ -512,6 +513,7 @@ } } history = history; + return; // Patches history.messages directly; skip the trailing write-back. } else if (type === 'chat:message:favorite') { // Update message favorite status message.favorite = data.favorite; @@ -673,7 +675,7 @@ if ( $selectedFolder && selectedModels.filter((modelId) => modelId !== '').length > 0 && - JSON.stringify($selectedFolder?.data?.model_ids) !== JSON.stringify(selectedModels) + !equal($selectedFolder?.data?.model_ids, selectedModels) ) { const res = await updateFolderById(localStorage.token, $selectedFolder.id, { data: { @@ -755,10 +757,7 @@ const selectedFolderSubscribe = selectedFolder.subscribe(async (folder) => { await tick(); - if ( - folder?.data?.model_ids && - JSON.stringify(selectedModels) !== JSON.stringify(folder.data.model_ids) - ) { + if (folder?.data?.model_ids && !equal(selectedModels, folder.data.model_ids)) { selectedModels = folder.data.model_ids; console.log('Set selectedModels from folder data:', selectedModels); @@ -1834,8 +1833,7 @@ ); chatFiles = chatFiles.filter( // Remove duplicates - (item, index, array) => - array.findIndex((i) => JSON.stringify(i) === JSON.stringify(item)) === index + (item, index, array) => array.findIndex((i) => equal(i, item)) === index ); // Create user message @@ -1879,7 +1877,7 @@ $models.map((m) => m.id).includes(modelId) ? modelId : '' ); - if (JSON.stringify(selectedModels) !== JSON.stringify(_selectedModels)) { + if (!equal(selectedModels, _selectedModels)) { selectedModels = _selectedModels; } @@ -2174,10 +2172,7 @@ ) ); // Remove duplicates - files = files.filter( - (item, index, array) => - array.findIndex((i) => JSON.stringify(i) === JSON.stringify(item)) === index - ); + files = files.filter((item, index, array) => array.findIndex((i) => equal(i, item)) === index); scrollToBottom(); eventTarget.dispatchEvent( @@ -2306,6 +2301,9 @@ // Use the user-selected terminal from the dropdown const activeTerminalId = $selectedTerminalId ?? null; + // Only send terminal_id if the model has terminal capability enabled + const terminalEnabled = model.info?.meta?.capabilities?.terminal ?? true; + const res = await generateOpenAIChatCompletion( localStorage.token, { @@ -2323,7 +2321,7 @@ filter_ids: selectedFilterIds.length > 0 ? selectedFilterIds : undefined, tool_ids: toolIds.length > 0 ? toolIds : undefined, skill_ids: skillIds.length > 0 ? skillIds : undefined, - terminal_id: activeTerminalId ?? undefined, + terminal_id: terminalEnabled ? (activeTerminalId ?? undefined) : undefined, tool_servers: [ ...($toolServers ?? []).filter( (server, idx) => toolServerIds.includes(idx) || toolServerIds.includes(server?.id) @@ -2408,8 +2406,11 @@ taskIds = newTaskIds; } - // Backend returns chat_id for new chats — set store + URL - if (res.chat_id && $chatId !== res.chat_id) { + // Backend returns chat_id for new chats — set store + URL. + // Only update if the user hasn't navigated to a different chat + // while the request was in flight (prevents overwriting $chatId + // and causing spurious toast notifications / state duplication). + if (res.chat_id && $chatId !== res.chat_id && $chatId === _chatId) { await chatId.set(res.chat_id); if (!$temporaryChatEnabled) { window.history.replaceState(history.state, '', `/c/${res.chat_id}`); @@ -3007,7 +3008,7 @@ if (e.detail || files.length > 0) { await tick(); - submitHandler(e.detail.replaceAll('\n\n', '\n')); + submitHandler(e.detail); } }} /> @@ -3050,7 +3051,7 @@ clearDraft(); if (e.detail || files.length > 0) { await tick(); - submitHandler(e.detail.replaceAll('\n\n', '\n')); + submitHandler(e.detail); } }} /> diff --git a/src/lib/components/chat/ChatControls.svelte b/src/lib/components/chat/ChatControls.svelte index 3cbcc7ed87..8ac5f06617 100644 --- a/src/lib/components/chat/ChatControls.svelte +++ b/src/lib/components/chat/ChatControls.svelte @@ -72,7 +72,10 @@ $: showControlsTab = $user?.role === 'admin' || ($user?.permissions?.chat?.controls ?? true); $: showFilesTab = - !!$selectedTerminalId || + ($selectedTerminalId && + (($terminalServers ?? []).some((t) => t.id && t.id === $selectedTerminalId) || + $user?.role === 'admin' || + ($user?.permissions?.features?.direct_tool_servers ?? true))) || (codeInterpreterEnabled && $config?.code?.interpreter_engine !== 'jupyter'); $: showOverviewTab = hasMessages; @@ -96,13 +99,22 @@ } // Auto-open Files tab when a terminal is selected (suppress panel open when full-screen) - $: if ($selectedTerminalId) { + $: if ($selectedTerminalId && showFilesTab) { activeTab = 'files'; if (largeScreen) { showControls.set(true); } } + // Clear selected direct terminal if user lost permission + $: if ( + $selectedTerminalId && + !($terminalServers ?? []).some((t) => t.id && t.id === $selectedTerminalId) && + !($user?.role === 'admin' || ($user?.permissions?.features?.direct_tool_servers ?? true)) + ) { + selectedTerminalId.set(null); + } + // Attach a terminal file to the chat input const handleTerminalAttach = async (blob: Blob, name: string, contentType: string) => { const tempItemId = uuidv4(); diff --git a/src/lib/components/chat/FileNav/FileEntryRow.svelte b/src/lib/components/chat/FileNav/FileEntryRow.svelte index 93baf941fa..ef56c2c6b5 100644 --- a/src/lib/components/chat/FileNav/FileEntryRow.svelte +++ b/src/lib/components/chat/FileNav/FileEntryRow.svelte @@ -1,4 +1,5 @@ diff --git a/src/lib/components/chat/Messages/UserMessage.svelte b/src/lib/components/chat/Messages/UserMessage.svelte index ec48a2e1ff..acc73c6446 100644 --- a/src/lib/components/chat/Messages/UserMessage.svelte +++ b/src/lib/components/chat/Messages/UserMessage.svelte @@ -7,6 +7,7 @@ import { user as _user } from '$lib/stores'; import { copyToClipboard as _copyToClipboard, formatDate } from '$lib/utils'; import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants'; + import equal from 'fast-deep-equal'; import Name from './Name.svelte'; import ProfileImage from './ProfileImage.svelte'; @@ -58,7 +59,7 @@ if (source) { if (message.content !== source.content) { message = structuredClone(source); - } else if (JSON.stringify(message) !== JSON.stringify(source)) { + } else if (!equal(message, source)) { message = structuredClone(source); } } @@ -550,8 +551,12 @@ class="{($settings?.highContrastMode ?? false) ? '' : 'invisible group-hover:visible'} p-1 rounded-sm dark:hover:text-white hover:text-black transition" - on:click={() => { - showDeleteConfirm = true; + on:click={(e) => { + if (e.shiftKey) { + deleteMessageHandler(); + } else { + showDeleteConfirm = true; + } }} > m.id).includes(model) ? model : '' ); - if (JSON.stringify(_selectedModels) !== JSON.stringify(selectedModels)) { + if (!equal(_selectedModels, selectedModels)) { selectedModels = _selectedModels; } } diff --git a/src/lib/components/chat/Placeholder.svelte b/src/lib/components/chat/Placeholder.svelte index 76d1ecff02..8c998b357d 100644 --- a/src/lib/components/chat/Placeholder.svelte +++ b/src/lib/components/chat/Placeholder.svelte @@ -106,7 +106,7 @@ }} /> {:else} -
+
{#each models as model, modelIdx} diff --git a/src/lib/components/chat/SettingsModal.svelte b/src/lib/components/chat/SettingsModal.svelte index a112400558..ffc01f531d 100644 --- a/src/lib/components/chat/SettingsModal.svelte +++ b/src/lib/components/chat/SettingsModal.svelte @@ -31,11 +31,16 @@ const i18n = getContext('i18n'); - export let show = false; + export let show: boolean | string = false; $: if (show) { + if (typeof show === 'string') { + selectedTab = show; + show = true; + } addScrollListener(); } else { + selectedTab = 'general'; removeScrollListener(); } diff --git a/src/lib/components/chat/ShareChatModal.svelte b/src/lib/components/chat/ShareChatModal.svelte index 1c02f6481d..7aa82df34c 100644 --- a/src/lib/components/chat/ShareChatModal.svelte +++ b/src/lib/components/chat/ShareChatModal.svelte @@ -3,24 +3,32 @@ import { models, config } from '$lib/stores'; import { toast } from 'svelte-sonner'; - import { deleteSharedChatById, getChatById, shareChatById } from '$lib/apis/chats'; + import { + deleteSharedChatById, + getChatById, + shareChatById, + getChatAccessGrants, + updateChatAccessGrants + } from '$lib/apis/chats'; import { copyToClipboard } from '$lib/utils'; import Modal from '../common/Modal.svelte'; import Link from '../icons/Link.svelte'; import XMark from '$lib/components/icons/XMark.svelte'; + import AccessControl from '$lib/components/workspace/common/AccessControl.svelte'; export let chatId; let chat = null; let shareUrl = null; + let accessGrants: any[] = []; const i18n = getContext('i18n'); const shareLocalChat = async () => { const _chat = chat; const sharedChat = await shareChatById(localStorage.token, chatId); - shareUrl = `${window.location.origin}/s/${sharedChat.id}`; + shareUrl = `${window.location.origin}/s/${sharedChat.share_id}`; console.log(shareUrl); chat = await getChatById(localStorage.token, chatId); @@ -54,6 +62,25 @@ ); }; + const loadAccessGrants = async () => { + if (!chatId) return; + try { + accessGrants = (await getChatAccessGrants(localStorage.token, chatId)) ?? []; + } catch (e) { + console.error('Failed to load access grants', e); + accessGrants = []; + } + }; + + const saveAccessGrants = async () => { + try { + await updateChatAccessGrants(localStorage.token, chatId, accessGrants); + toast.success($i18n.t('Access updated')); + } catch (e) { + toast.error(`${e}`); + } + }; + export let show = false; const isDifferentChat = (_chat) => { @@ -73,8 +100,10 @@ if (isDifferentChat(_chat)) { chat = _chat; } + await loadAccessGrants(); } else { chat = null; + accessGrants = []; console.log(chat); } })(); @@ -97,8 +126,8 @@
{#if chat} -
-
+
+ -
-
-
- {#if $config?.features.enable_community_sharing} - - {/if} - - -
+ {#if chat.share_id} +
+
+ {/if} + +
+ {#if $config?.features.enable_community_sharing} + + {/if} + +
{/if} diff --git a/src/lib/components/common/RichTextInput.svelte b/src/lib/components/common/RichTextInput.svelte index 4cdd8878f1..8c4006d280 100644 --- a/src/lib/components/common/RichTextInput.svelte +++ b/src/lib/components/common/RichTextInput.svelte @@ -1,6 +1,7 @@ + { + if (e.key === 'Shift') shiftKey = true; + }} + on:keyup={(e) => { + if (e.key === 'Shift') shiftKey = false; + }} +/> + {$i18n.t('Settings')}
- {#if $user?.role === 'admin' || $user?.permissions?.features?.automations} -
{ - if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) return; - e.preventDefault(); - show = false; - goto('/automations'); - if ($mobile) { - await tick(); - showSidebar.set(false); - } - }} - > -
- - - -
-
{$i18n.t('Automations')}
-
- {/if} - {#if role === 'admin'} { @@ -261,7 +265,7 @@ } e.preventDefault(); show = false; - goto('/playground'); + goto('/admin'); if ($mobile) { await tick(); showSidebar.set(false); @@ -269,9 +273,9 @@ }} >
- +
-
{$i18n.t('Playground')}
+
{$i18n.t('Admin Panel')}
{/if} @@ -296,29 +300,261 @@
{$i18n.t('Archived Chats')}
+
+ + {#if $user?.role === 'admin' || $user?.permissions?.workspace?.models || $user?.permissions?.workspace?.knowledge || $user?.permissions?.workspace?.prompts || $user?.permissions?.workspace?.tools} + + {/if} + + {#if ($config?.features?.enable_notes ?? false) && ($user?.role === 'admin' || ($user?.permissions?.features?.notes ?? true))} + + {/if} + + {#if $config?.features?.enable_calendar && ($user?.role === 'admin' || $user?.permissions?.features?.calendar)} + + {/if} + + {#if $config?.features?.enable_automations && ($user?.role === 'admin' || $user?.permissions?.features?.automations)} + + {/if} + {#if role === 'admin'} - { - if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) { - return; - } - e.preventDefault(); - show = false; - goto('/admin'); - if ($mobile) { - await tick(); - showSidebar.set(false); - } - }} - > -
- -
-
{$i18n.t('Admin Panel')}
-
+ {/if} {#if help} diff --git a/src/lib/components/notes/NoteEditor.svelte b/src/lib/components/notes/NoteEditor.svelte index 8f387ed6ed..4216243857 100644 --- a/src/lib/components/notes/NoteEditor.svelte +++ b/src/lib/components/notes/NoteEditor.svelte @@ -8,6 +8,7 @@ import { marked } from 'marked'; import { toast } from 'svelte-sonner'; + import equal from 'fast-deep-equal'; import { goto } from '$app/navigation'; @@ -226,7 +227,7 @@ } function areContentsEqual(a, b) { - return JSON.stringify(a) === JSON.stringify(b); + return equal(a, b); } function insertNoteVersion(note) { diff --git a/src/lib/components/workspace/Models/BuiltinTools.svelte b/src/lib/components/workspace/Models/BuiltinTools.svelte index b171c85e46..fe99005688 100644 --- a/src/lib/components/workspace/Models/BuiltinTools.svelte +++ b/src/lib/components/workspace/Models/BuiltinTools.svelte @@ -50,21 +50,16 @@ automations: { label: $i18n.t('Automations'), description: $i18n.t('Create and manage scheduled automations') + }, + calendar: { + label: $i18n.t('Calendar'), + description: $i18n.t('List calendars, search, create, update, and delete calendar events') } }; const allTools = Object.keys(toolLabels); export let builtinTools: Record = {}; - - // Initialize missing keys to true (default enabled) - $: { - for (const tool of allTools) { - if (!(tool in builtinTools)) { - builtinTools[tool] = true; - } - } - }
@@ -77,10 +72,12 @@ { - builtinTools = { - ...builtinTools, - [tool]: e.detail === 'checked' - }; + if (e.detail === 'checked') { + delete builtinTools[tool]; + } else { + builtinTools[tool] = false; + } + builtinTools = builtinTools; }} /> diff --git a/src/lib/components/workspace/Models/Capabilities.svelte b/src/lib/components/workspace/Models/Capabilities.svelte index 57810c2303..627a1b0b3f 100644 --- a/src/lib/components/workspace/Models/Capabilities.svelte +++ b/src/lib/components/workspace/Models/Capabilities.svelte @@ -31,6 +31,12 @@ label: $i18n.t('Code Interpreter'), description: $i18n.t('Model can execute code and perform calculations') }, + terminal: { + label: $i18n.t('Terminal'), + description: $i18n.t( + 'Model can access Open Terminal for command execution and file management' + ) + }, usage: { label: $i18n.t('Usage'), description: $i18n.t( @@ -60,6 +66,7 @@ web_search?: boolean; image_generation?: boolean; code_interpreter?: boolean; + terminal?: boolean; usage?: boolean; citations?: boolean; status_updates?: boolean; diff --git a/src/lib/components/workspace/Models/ModelEditor.svelte b/src/lib/components/workspace/Models/ModelEditor.svelte index c41f51495a..bedc0920be 100644 --- a/src/lib/components/workspace/Models/ModelEditor.svelte +++ b/src/lib/components/workspace/Models/ModelEditor.svelte @@ -839,9 +839,11 @@
{/if} -
- -
+ {#if capabilities.terminal} +
+ +
+ {/if}
diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 006304bbb4..b25ec0f848 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -104,6 +104,7 @@ export const DEFAULT_CAPABILITIES = { web_search: true, image_generation: true, code_interpreter: true, + terminal: true, citations: true, status_updates: true, usage: undefined, diff --git a/src/lib/i18n/locales/ar-BH/translation.json b/src/lib/i18n/locales/ar-BH/translation.json index c390eff0fd..13e9aed4e9 100644 --- a/src/lib/i18n/locales/ar-BH/translation.json +++ b/src/lib/i18n/locales/ar-BH/translation.json @@ -37,8 +37,13 @@ "{{user}}'s Chats": "دردشات {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} مطلوب", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -51,6 +56,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "الحساب", "Account Activation Pending": "", @@ -76,9 +82,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "إضافة ملفات", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "إضافة ذكرايات", @@ -114,6 +122,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -202,6 +211,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +286,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -412,6 +424,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "اتصالات", @@ -443,6 +456,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "أنسخ الرابط", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -523,8 +537,11 @@ "Delete All Chats": "حذف جميع الدردشات", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "حذف المحادثه.", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -831,6 +848,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -879,6 +900,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "فشل في إنشاء مفتاح API.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1200,6 +1222,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1210,6 +1233,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1277,6 +1301,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "تم تحميل النموذج '{{modelName}}' بنجاح", "Model '{{modelTag}}' is already in queue for downloading.": "النموذج '{{modelTag}}' موجود بالفعل في قائمة الانتظار للتحميل", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "نموذج {{modelName}} غير قادر على الرؤية", "Model {{name}} is now {{status}}": "نموذج {{name}} هو الآن {{status}}", @@ -1284,6 +1309,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1317,6 +1343,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "المزيد", "More Concise": "", @@ -1335,6 +1362,7 @@ "New Automation": "", "New Button": "", "New Chat": "دردشة جديدة", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1504,6 +1532,7 @@ "Password": "الباسورد", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF ملف (.pdf)", "PDF Extract Images (OCR)": "PDF أستخرج الصور (OCR)", @@ -1611,6 +1640,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "سجل صوت", "Redirecting you to Open WebUI Community": "OpenWebUI إعادة توجيهك إلى مجتمع ", @@ -1634,6 +1664,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "إزالة", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1652,6 +1683,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "إعادة تقييم النموذج", "Reset": "", @@ -1883,7 +1915,15 @@ "Start a new conversation": "", "Start of the channel": "بداية القناة", "Start Tag": "", + "Starting in {{count}} minutes_zero": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_two": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1996,6 +2036,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "شرح شامل", "Thought": "", @@ -2015,6 +2056,7 @@ "Title cannot be an empty string.": "العنوان مطلوب", "Title Generation": "", "Title Generation Prompt": "موجه إنشاء العنوان", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "للوصول إلى أسماء الموديلات المتاحة للتنزيل،", "To access the GGUF models available for downloading,": "للوصول إلى الموديلات GGUF المتاحة للتنزيل،", @@ -2081,6 +2123,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2185,6 +2228,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2192,6 +2236,7 @@ "What is shared:": "", "What's New in": "ما هو الجديد", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/ar/translation.json b/src/lib/i18n/locales/ar/translation.json index 50efd0c748..3eb53e68bd 100644 --- a/src/lib/i18n/locales/ar/translation.json +++ b/src/lib/i18n/locales/ar/translation.json @@ -37,8 +37,13 @@ "{{user}}'s Chats": "محادثات المستخدم {{user}}", "{{webUIName}} Backend Required": "يتطلب الخلفية الخاصة بـ {{webUIName}}", "*Prompt node ID(s) are required for image generation": "*معرّف/معرّفات عقدة الموجه مطلوبة لتوليد الصور", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "يتوفر الآن إصدار جديد (v{{LATEST_VERSION}}).", @@ -51,6 +56,7 @@ "Access Control": "التحكم في الوصول", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "متاح لجميع المستخدمين", "Account": "الحساب", "Account Activation Pending": "انتظار تفعيل الحساب", @@ -76,9 +82,11 @@ "Add content here": "أضف المحتوى هنا", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "إضافة ملفات", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "إضافة ذاكرة", @@ -114,6 +122,7 @@ "AI": "", "All": "الكل", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "تم حذف جميع النماذج بنجاح", @@ -202,6 +211,7 @@ "Ask a question": "اطرح سؤالاً", "Assistant": "المساعد", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +286,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "التقويم", + "Calendar deleted": "", + "Calendars": "", "Call": "مكالمة", "Call feature is not supported when using Web STT engine": "ميزة الاتصال غير مدعومة عند استخدام محرك Web STT", "Camera": "الكاميرا", @@ -412,6 +424,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "الاتصالات", @@ -443,6 +456,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "نسخ الرابط", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "نسخ إلى الحافظة", @@ -523,8 +537,11 @@ "Delete All Chats": "حذف جميع الدردشات", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "حذف المحادثه.", "Delete chat?": "هل تريد حذف المحادثة؟", + "Delete Event": "", "Delete File": "", "Delete folder?": "هل تريد حذف المجلد؟", "Delete function?": "هل تريد حذف الوظيفة؟", @@ -831,6 +848,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "التقييمات", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "مفتاح API لـ Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "مثال: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "مثال: ALL", @@ -879,6 +900,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "فشل في إنشاء مفتاح API.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1200,6 +1222,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "جارٍ الاستماع...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1210,6 +1233,7 @@ "local": "", "Local": "محلي", "Local Task Model": "", + "Location": "", "Location access not allowed": "لا يُسمح بالوصول إلى الموقع", "Lost": "ضائع", "Low": "", @@ -1277,6 +1301,7 @@ "Model": "النموذج", "Model '{{modelName}}' has been successfully downloaded.": "تم تحميل النموذج '{{modelName}}' بنجاح", "Model '{{modelTag}}' is already in queue for downloading.": "النموذج '{{modelTag}}' موجود بالفعل في قائمة الانتظار للتحميل", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "نموذج {{modelName}} غير قادر على الرؤية", "Model {{name}} is now {{status}}": "نموذج {{name}} هو الآن {{status}}", @@ -1284,6 +1309,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "النموذج يقبل إدخالات الصور", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1317,6 +1343,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "مفتاح API لـ Mojeek Search", + "Month": "", "Monthly": "", "More": "المزيد", "More Concise": "", @@ -1335,6 +1362,7 @@ "New Automation": "", "New Button": "", "New Chat": "دردشة جديدة", + "New Event": "", "New File": "", "New Folder": "مجلد جديد", "New Function": "", @@ -1504,6 +1532,7 @@ "Password": "الباسورد", "Passwords do not match.": "", "Paste Large Text as File": "الصق نصًا كبيرًا كملف", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF ملف (.pdf)", "PDF Extract Images (OCR)": "PDF أستخرج الصور (OCR)", @@ -1611,6 +1640,7 @@ "Reasoning Effort": "جهد الاستدلال", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "سجل صوت", "Redirecting you to Open WebUI Community": "OpenWebUI إعادة توجيهك إلى مجتمع ", @@ -1634,6 +1664,7 @@ "Relevance": "الصلة", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "إزالة", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1652,6 +1683,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "إعادة تقييم النموذج", "Reset": "إعادة تعيين", @@ -1883,7 +1915,15 @@ "Start a new conversation": "", "Start of the channel": "بداية القناة", "Start Tag": "", + "Starting in {{count}} minutes_zero": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_two": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1996,6 +2036,7 @@ "This will delete {{NAME}} and all its contents.": "هذا سيحذف {{NAME}} وكل محتوياته.", "This will delete all models including custom models": "هذا سيحذف جميع النماذج بما في ذلك النماذج المخصصة", "This will delete all models including custom models and cannot be undone.": "هذا سيحذف جميع النماذج بما في ذلك المخصصة ولا يمكن التراجع عن هذا الإجراء.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "هذا سيؤدي إلى إعادة تعيين قاعدة المعرفة ومزامنة جميع الملفات. هل ترغب في المتابعة؟", "Thorough explanation": "شرح شامل", "Thought": "", @@ -2015,6 +2056,7 @@ "Title cannot be an empty string.": "العنوان مطلوب", "Title Generation": "توليد العنوان", "Title Generation Prompt": "موجه إنشاء العنوان", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "للوصول إلى أسماء الموديلات المتاحة للتنزيل،", "To access the GGUF models available for downloading,": "للوصول إلى الموديلات GGUF المتاحة للتنزيل،", @@ -2081,6 +2123,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "اكشف الأسرار", "Unpin": "إزالة التثبيت", + "Unpin from Sidebar": "", "Unravel secrets": "فكّ الأسرار", "Unshare Chat": "", "Unsupported file type.": "", @@ -2185,6 +2228,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "ستقوم WebUI بإرسال الطلبات إلى \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "ستقوم WebUI بإرسال الطلبات إلى \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "ما الذي تحاول تحقيقه؟", "What are you working on?": "على ماذا تعمل؟", @@ -2192,6 +2236,7 @@ "What is shared:": "", "What's New in": "ما هو الجديد", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "عند التفعيل، سيستجيب النموذج لكل رسالة في المحادثة بشكل فوري، مولدًا الرد بمجرد إرسال المستخدم لرسالته. هذا الوضع مفيد لتطبيقات الدردشة الحية، لكنه قد يؤثر على الأداء في الأجهزة الأبطأ.", "wherever you are": "أينما كنت", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/az-AZ/translation.json b/src/lib/i18n/locales/az-AZ/translation.json index 5aa624f6d3..8eec5e5732 100644 --- a/src/lib/i18n/locales/az-AZ/translation.json +++ b/src/lib/i18n/locales/az-AZ/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} adlı istifadəçinin söhbətləri", "{{webUIName}} Backend Required": "{{webUIName}} üçün Backend tələb olunur", "*Prompt node ID(s) are required for image generation": "*Şəkil yaradılması üçün sorğu (prompt) qovşaq ID-ləri tələb olunur", + "1 hour before": "", "1 Source": "1 Mənbə", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1 dəq əvvəl", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "İnsanların üzv kimi qoşulduğu əməkdaşlıq kanalı", "A discussion channel where access is controlled by groups and permissions": "Girişin qruplar və icazələrlə idarə olunduğu müzakirə kanalı", "A new version (v{{LATEST_VERSION}}) is now available.": "Yeni versiya (v{{LATEST_VERSION}}) artıq mövcuddur.", @@ -47,6 +52,7 @@ "Access Control": "Girişə nəzarət", "Access Grants": "Giriş icazələri", "Access List": "Giriş siyahısı", + "Access updated": "", "Accessible to all users": "Bütün istifadəçilər üçün əlçatandır", "Account": "Hesab", "Account Activation Pending": "Hesabın aktivləşdirilməsi gözlənilir", @@ -72,9 +78,11 @@ "Add content here": "Məzmunu buraya əlavə edin", "Add Custom Parameter": "Fərdi parametr əlavə et", "Add Custom Prompt": "Fərdi prompt əlavə et", + "Add description": "", "Add Details": "Detallar əlavə et", "Add Files": "Fayl əlavə et", "Add Image": "Şəkil əlavə et", + "Add location": "", "Add Member": "Üzv əlavə et", "Add Members": "Üzvlər əlavə et", "Add Memory": "Yaddaş əlavə et", @@ -110,6 +118,7 @@ "AI": "Süni İntellekt (Sİ)", "All": "Hamısı", "All chats have been unarchived.": "Bütün çatlar arxivdən çıxarıldı.", + "All day": "", "All models are now hidden": "Bütün modellər indi gizlidir", "All models are now visible": "Bütün modellər indi görünür", "All models deleted successfully": "Bütün modellər uğurla silindi", @@ -198,6 +207,7 @@ "Ask a question": "Sual verin", "Assistant": "Köməkçi", "Async Embedding Processing": "Asinxron Yerləşdirmə (Embedding) Emalı", + "At time of event": "", "Attach File From Knowledge": "Bilik bazasından fayl əlavə et", "Attach Files": "", "Attach Knowledge": "Bilik əlavə et", @@ -272,6 +282,8 @@ "Bypass Web Loader": "Veb Yükləyicidən Yan Keç", "Cache Base Model List": "Əsas Model Siyahısını Keşlə", "Calendar": "Təqvim", + "Calendar deleted": "", + "Calendars": "", "Call": "Zəng", "Call feature is not supported when using Web STT engine": "Veb STT mühərriki istifadə edildikdə zəng funksiyası dəstəklənmir", "Camera": "Kamera", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Öz OpenAPI uyğun xarici alət serverlərinizə qoşulun.", "Connected ({{type}})": "", "Connection failed": "Bağlantı uğursuz oldu", + "Connection lost. Reconnecting...": "", "Connection successful": "Bağlantı uğurludur", "Connection Type": "Bağlantı növü", "Connections": "Bağlantılar", @@ -439,6 +452,7 @@ "Copy Last Response": "Sonuncu cavabı kopyala", "Copy link": "Linki kopyala", "Copy Link": "Linki Kopyala", + "Copy Path": "", "Copy Prompt": "Göstərişi (Prompt) kopyala", "Copy Share Link": "Paylaşım linkini kopyala", "Copy to clipboard": "Mübadilə buferinə kopyala", @@ -519,8 +533,11 @@ "Delete All Chats": "Bütün çatları sil", "Delete all contents inside this folder": "Bu qovluğun daxilindəki bütün məzmunu sil", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Çatı sil", "Delete chat?": "Çat silinsin?", + "Delete Event": "", "Delete File": "Faylı sil", "Delete folder?": "Qovluq silinsin?", "Delete function?": "Funksiya silinsin?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Xəta: '{{modelId}}' ID-li model artıq mövcuddur. Davam etmək üçün fərqli bir ID seçin.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Xəta: Model ID-si boş ola bilməz. Davam etmək üçün etibarlı bir ID daxil edin.", "Evaluations": "Qiymətləndirmələr", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API Açarı", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Nümunə: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Nümunə: ALL (HAMISI)", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "{{URL}} terminal serverinə qoşulmaq mümkün olmadı", "Failed to copy link": "Link kopyalanmadı", "Failed to create API Key.": "API açarı yaradılmadı.", + "Failed to delete calendar": "", "Failed to delete note": "Qeyd silinmədi", "Failed to download image": "Şəkil yüklənmədi", "Failed to extract content from the file: {{error}}": "Fayldan məzmun çıxarıla bilmədi: {{error}}", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Eyni vaxtda aparılan axtarış sorğularını məhdudlaşdırın. 0 = limitsiz (standart). Ardıcıl icra üçün 1 təyin edin.", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Eyni vaxtda olan yerləşdirmə (embedding) sorğularının sayını məhdudlaşdırır. Limitsiz üçün 0 təyin edin.", "List": "Siyahı", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Dinlənilir...", "Live": "Canlı", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "yerli", "Local": "Yerli", "Local Task Model": "Yerli tapşırıq modeli", + "Location": "", "Location access not allowed": "Məkan girişinə icazə verilmir", "Lost": "İtirildi", "Low": "Aşağı", @@ -1273,6 +1297,7 @@ "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "'{{modelName}}' modeli uğurla yükləndi.", "Model '{{modelTag}}' is already in queue for downloading.": "'{{modelTag}}' modeli artıq yükləmə növbəsindədir.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "{{modelName}} modeli görüntünü tanıma (vision) qabiliyyətinə malik deyil", "Model {{name}} is now {{status}}": "{{name}} modeli indi {{status}} statusundadır", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "{{name}} modeli artıq görünəndir", "Model accepts file inputs": "Model fayl girişlərini qəbul edir", "Model accepts image inputs": "Model şəkil girişlərini qəbul edir", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Model kod icra edə və hesablamalar apara bilər", "Model can generate images based on text prompts": "Model mətn göstərişləri əsasında şəkillər yarada bilər", "Model can search the web for information": "Model məlumat üçün vebdə axtarış edə bilər", @@ -1313,6 +1339,7 @@ "Models Sharing": "Modellərin paylaşılması", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Axtarış API Açarı", + "Month": "", "Monthly": "", "More": "Daha çox", "More Concise": "Daha yığcam", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "Yeni Düymə", "New Chat": "Yeni Çat", + "New Event": "", "New File": "Yeni Fayl", "New Folder": "Yeni Qovluq", "New Function": "Yeni Funksiya", @@ -1500,6 +1528,7 @@ "Password": "Şifrə", "Passwords do not match.": "Şifrələr uyğun gəlmir.", "Paste Large Text as File": "Böyük mətni fayl kimi yapışdır", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF sənədi (.pdf)", "PDF Extract Images (OCR)": "PDF-dən şəkillərin çıxarılması (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Mühakimə səyi", "Reasoning Tags": "Mühakimə etiketləri", "Recently Used": "", + "Reconnected": "", "Record": "Yaz (səs)", "Record voice": "Səsi yaz", "Redirecting you to Open WebUI Community": "Open WebUI İcmasına yönləndirilirsiniz", @@ -1630,6 +1660,7 @@ "Relevance": "Uyğunluq", "Relevance Threshold": "Uyğunluq həddi", "Remember Dismissal": "İmtinanı yadda saxla", + "Reminder": "", "Remove": "Çıxar", "Remove {{MODELID}} from list.": "{{MODELID}} siyahıdan çıxarılsın.", "Remove action": "Əməliyyatı çıxar", @@ -1648,6 +1679,7 @@ "Reply to thread...": "Mövzuya cavab yaz...", "Replying to {{NAME}}": "{{NAME}} adlı istifadəçiyə cavab verilir", "required": "tələb olunur", + "Reranking Batch Size": "", "Reranking Engine": "Yenidən sıralama mühərriki", "Reranking Model": "Yenidən sıralama modeli", "Reset": "Sıfırla", @@ -1875,7 +1907,11 @@ "Start a new conversation": "Yeni söhbətə başlayın", "Start of the channel": "Kanalın başlanğıcı", "Start Tag": "Start Tag", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Starting kernel...", + "Starting now": "", "State": "", "Status": "Status", "Status cleared successfully": "Status uğurla təmizləndi", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Bu, {{NAME}} adlı elementi və onun bütün məzmununu siləcək.", "This will delete all models including custom models": "Bu, fərdi modellər də daxil olmaqla bütün modelləri siləcək", "This will delete all models including custom models and cannot be undone.": "Bu, fərdi modellər də daxil olmaqla bütün modelləri siləcək və geri qaytarıla bilməz.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Bu, bilik bazasını sıfırlayacaq və bütün faylları sinxronizasiya edəcək. Davam etmək istəyirsiniz?", "Thorough explanation": "Ətraflı izahat", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Başlıq boş qala bilməz.", "Title Generation": "Başlıq yaradılması", "Title Generation Prompt": "Başlıq yaradılması üçün göstəriş", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Yükləmək üçün mövcud model adlarına daxil olmaq üçün,", "To access the GGUF models available for downloading,": "Yükləmək üçün mövcud GGUF modellərinə daxil olmaq üçün,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} sonra yaddaşdan silinir", "Unlock mysteries": "Sirrləri açın", "Unpin": "Sabitlənmişdən çıxar", + "Unpin from Sidebar": "", "Unravel secrets": "Gizlinləri üzə çıxarın", "Unshare Chat": "Çatı paylaşımı dayandır", "Unsupported file type.": "Dəstəklənməyən fayl növü.", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI \"{{url}}\" ünvanına sorğular göndərəcək", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI \"{{url}}/api/chat\" ünvanına sorğular göndərəcək", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" ünvanına sorğular göndərəcək", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Nəyə nail olmaq istəyirsiniz?", "What are you working on?": "Nəyin üzərində işləyirsiniz?", @@ -2184,6 +2224,7 @@ "What is shared:": "Nələr paylaşılır:", "What's New in": "Yeniliklər:", "What's on your mind?": "Ağlınızda nə var?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Aktiv edildikdə, model hər bir mesajı real vaxt rejimində cavablandıracaq. Bu rejim canlı söhbət tətbiqləri üçün faydalıdır, lakin zəif avadanlıqlarda performansa təsir edə bilər.", "wherever you are": "harada olursunuzsa olun", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Nəticənin səhifələrə bölünüb-bölünməməsi. Hər səhifə üfüqi xətt və səhifə nömrəsi ilə ayrılacaq. İlkin olaraq False (Xeyr) seçilir.", diff --git a/src/lib/i18n/locales/bg-BG/translation.json b/src/lib/i18n/locales/bg-BG/translation.json index 07ca792153..685debf883 100644 --- a/src/lib/i18n/locales/bg-BG/translation.json +++ b/src/lib/i18n/locales/bg-BG/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}'s чатове", "{{webUIName}} Backend Required": "{{webUIName}} Изисква се Бекенд", "*Prompt node ID(s) are required for image generation": "*Идентификатор(ите) на възел-а се изисква(т) за генериране на изображения", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Вече е налична нова версия (v{{LATEST_VERSION}}).", @@ -47,6 +52,7 @@ "Access Control": "Контрол на достъпа", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Достъпно за всички потребители", "Account": "Акаунт", "Account Activation Pending": "Активирането на акаунта е в процес на изчакване", @@ -72,9 +78,11 @@ "Add content here": "Добавете съдържание тук", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Добавяне на Файлове", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Добавяне на Памет", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Всички модели са изтрити успешно", @@ -198,6 +207,7 @@ "Ask a question": "Задайте въпрос", "Assistant": "Асистент", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Календар", + "Calendar deleted": "", + "Calendars": "", "Call": "Обаждане", "Call feature is not supported when using Web STT engine": "Функцията за обаждане не се поддържа при използването на Web STT двигател", "Camera": "Камера", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Връзки", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Копиране на връзка", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Копиране в клипборда", @@ -519,8 +533,11 @@ "Delete All Chats": "Изтриване на всички чатове", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Изтриване на Чат", "Delete chat?": "Изтриване на чата?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Изтриване на папката?", "Delete function?": "Изтриване на функцията?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Оценки", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "API ключ за Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Пример: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Пример: ВСИЧКИ", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Неуспешно създаване на API ключ.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Слушане...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "", "Local": "Локално", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Изгубено", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "Модел", "Model '{{modelName}}' has been successfully downloaded.": "Моделът '{{modelName}}' беше успешно свален.", "Model '{{modelTag}}' is already in queue for downloading.": "Моделът '{{modelTag}}' е вече в очакване за сваляне.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Моделът {{modelName}} не поддържа визуални възможности", "Model {{name}} is now {{status}}": "Моделът {{name}} сега е {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "Моделът приема входни изображения", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "API ключ за Mojeek Search", + "Month": "", "Monthly": "", "More": "Повече", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "Нов чат", + "New Event": "", "New File": "", "New Folder": "Нова папка", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "Парола", "Passwords do not match.": "", "Paste Large Text as File": "Поставете голям текст като файл", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF документ (.pdf)", "PDF Extract Images (OCR)": "Извличане на изображения от PDF (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Усилие за разсъждение", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Запиши", "Record voice": "Записване на глас", "Redirecting you to Open WebUI Community": "Пренасочване към OpenWebUI общността", @@ -1630,6 +1660,7 @@ "Relevance": "Релевантност", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Изтриване", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "Двигател за пренареждане", "Reranking Model": "Модел за преподреждане", "Reset": "Нулиране", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Начало на канала", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Това ще изтрие {{NAME}} и цялото му съдържание.", "This will delete all models including custom models": "Това ще изтрие всички модели, включително персонализираните модели", "This will delete all models including custom models and cannot be undone.": "Това ще изтрие всички модели, включително персонализираните модели, и не може да бъде отменено.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Това ще нулира базата знания и ще синхронизира всички файлове. Желаете ли да продължите?", "Thorough explanation": "Подробно обяснение", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Заглавието не може да бъде празно.", "Title Generation": "Генериране на заглавие", "Title Generation Prompt": "Промпт за генериране на заглавие", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "За достъп до наличните имена на моделите за изтегляне,", "To access the GGUF models available for downloading,": "За достъп до наличните GGUF модели за изтегляне,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Разкрий мистерии", "Unpin": "Откачи", + "Unpin from Sidebar": "", "Unravel secrets": "Разгадай тайни", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI ще прави заявки към \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI ще прави заявки към \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Какво се опитвате да постигнете?", "What are you working on?": "Върху какво работите?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "Какво е ново в", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Когато е активирано, моделът ще отговаря на всяко съобщение в чата в реално време, генерирайки отговор веднага щом потребителят изпрати съобщение. Този режим е полезен за приложения за чат на живо, но може да повлияе на производителността на по-бавен хардуер.", "wherever you are": "където и да сте", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/bn-BD/translation.json b/src/lib/i18n/locales/bn-BD/translation.json index a20abb0d9a..9437c8a347 100644 --- a/src/lib/i18n/locales/bn-BD/translation.json +++ b/src/lib/i18n/locales/bn-BD/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}র চ্যাটস", "{{webUIName}} Backend Required": "{{webUIName}} ব্যাকএন্ড আবশ্যক", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -47,6 +52,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "একাউন্ট", "Account Activation Pending": "", @@ -72,9 +78,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "ফাইল যোগ করুন", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "মেমোরি যোগ করুন", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -198,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "কানেকশনগুলো", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "লিংক কপি করুন", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -519,8 +533,11 @@ "Delete All Chats": "সব চ্যাট মুছে ফেলুন", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "চ্যাট মুছে ফেলুন", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "API Key তৈরি করা যায়নি।", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1206,6 +1229,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "'{{modelName}}' মডেল সফলভাবে ডাউনলোড হয়েছে।", "Model '{{modelTag}}' is already in queue for downloading.": "{{modelTag}} ডাউনলোডের জন্য আগে থেকেই অপেক্ষমান আছে।", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "মডেল {{modelName}} দৃষ্টি সক্ষম নয়", "Model {{name}} is now {{status}}": "মডেল {{name}} এখন {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "আরো", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "নতুন চ্যাট", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "পাসওয়ার্ড", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF ডকুমেন্ট (.pdf)", "PDF Extract Images (OCR)": "পিডিএফ এর ছবি থেকে লেখা বের করুন (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "ভয়েস রেকর্ড করুন", "Redirecting you to Open WebUI Community": "আপনাকে OpenWebUI কমিউনিটিতে পাঠানো হচ্ছে", @@ -1630,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "রিমুভ করুন", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "রির্যাক্টিং মডেল", "Reset": "", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "চ্যানেলের শুরু", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "পুঙ্খানুপুঙ্খ ব্যাখ্যা", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "শিরোনাম অবশ্যই একটি পাশাপাশি শব্দ হতে হবে।", "Title Generation": "", "Title Generation Prompt": "শিরোনামগঠন প্রম্পট", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "ডাউনলোডের জন্য এভেইলএবল মডেলের নামগুলো এক্সেস করতে,", "To access the GGUF models available for downloading,": "ডাউলোডের জন্য এভেইলএবল GGUF মডেলগুলো এক্সেস করতে,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "এতে নতুন কী", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/bo-TB/translation.json b/src/lib/i18n/locales/bo-TB/translation.json index fef2cb1847..a65771c7b5 100644 --- a/src/lib/i18n/locales/bo-TB/translation.json +++ b/src/lib/i18n/locales/bo-TB/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "{{user}} ཡི་ཁ་བརྡ།", "{{webUIName}} Backend Required": "{{webUIName}} རྒྱབ་སྣེ་དགོས།", "*Prompt node ID(s) are required for image generation": "*པར་བཟོའི་ཆེད་དུ་འགུལ་སློང་མདུད་ཚེག་གི་ ID(s) དགོས།", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "པར་གཞི་གསར་པ། (v{{LATEST_VERSION}}) ད་ལྟ་ཡོད།", @@ -46,6 +51,7 @@ "Access Control": "འཛུལ་སྤྱོད་ཚོད་འཛིན།", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "བེད་སྤྱོད་མཁན་ཡོངས་ལ་འཛུལ་སྤྱོད་ཆོག་པ།", "Account": "རྩིས་ཁྲ།", "Account Activation Pending": "རྩིས་ཁྲ་སྒུལ་བསྐྱོད་སྒུག་བཞིན་པ།", @@ -71,9 +77,11 @@ "Add content here": "ནང་དོན་འདིར་སྣོན་པ།", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "ཡིག་ཆ་སྣོན་པ།", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "དྲན་ཤེས་སྣོན་པ།", @@ -109,6 +117,7 @@ "AI": "", "All": "ཡོངས།", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "དཔེ་དབྱིབས་ཡོངས་རྫོགས་ལེགས་པར་བསུབས་ཟིན།", @@ -197,6 +206,7 @@ "Ask a question": "དྲི་བ་ཞིག་འདྲི་བ།", "Assistant": "ལག་རོགས་པ།", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -271,6 +281,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "ལོ་ཐོ།", + "Calendar deleted": "", + "Calendars": "", "Call": "སྐད་འབོད།", "Call feature is not supported when using Web STT engine": "Web STT མ་ལག་སྤྱོད་སྐབས་སྐད་འབོད་ཀྱི་ཁྱད་ཆོས་ལ་རྒྱབ་སྐྱོར་མེད།", "Camera": "པར་ཆས།", @@ -407,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "ཁྱེད་རང་གི་ OpenAPI དང་མཐུན་པའི་ཕྱི་རོལ་ལག་ཆའི་སར་བར་ལ་སྦྲེལ་བ།", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "སྦྲེལ་མཐུད།", @@ -438,6 +451,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "སྦྲེལ་ཐག་འདྲ་བཤུས།", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "སྦྱར་སྡེར་དུ་འདྲ་བཤུས།", @@ -518,8 +532,11 @@ "Delete All Chats": "ཁ་བརྡ་ཡོངས་རྫོགས་བསུབ་པ།", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "ཁ་བརྡ་བསུབ་པ།", "Delete chat?": "ཁ་བརྡ་བསུབ་པ།?", + "Delete Event": "", "Delete File": "", "Delete folder?": "ཡིག་སྣོད་བསུབ་པ།?", "Delete function?": "ལས་འགན་བསུབ་པ།?", @@ -826,6 +843,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "གདེང་འཇོག", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API ལྡེ་མིག", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "དཔེར་ན། (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "དཔེར་ན། ALL", @@ -874,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "API ལྡེ་མིག་བཟོ་མ་ཐུབ།", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1195,6 +1217,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "ཉན་བཞིན་པ།...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1205,6 +1228,7 @@ "local": "", "Local": "ས་གནས།", "Local Task Model": "", + "Location": "", "Location access not allowed": "གནས་ཡུལ་འཛུལ་སྤྱོད་ལ་གནང་བ་མ་སྤྲད།", "Lost": "བརླགས།", "Low": "", @@ -1272,6 +1296,7 @@ "Model": "དཔེ་དབྱིབས།", "Model '{{modelName}}' has been successfully downloaded.": "དཔེ་དབྱིབས། '{{modelName}}' ལེགས་པར་ཕབ་ལེན་བྱས་ཟིན།", "Model '{{modelTag}}' is already in queue for downloading.": "དཔེ་དབྱིབས། '{{modelTag}}' ཕབ་ལེན་གྱི་སྒུག་ཐོ་ནང་ཡོད་ཟིན།", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "དཔེ་དབྱིབས། {{modelName}} ལ་མཐོང་ནུས་མེད།", "Model {{name}} is now {{status}}": "དཔེ་དབྱིབས། {{name}} ད་ལྟ་ {{status}} ཡིན།", @@ -1279,6 +1304,7 @@ "Model {{name}} is now visible": "དཔེ་དབྱིབས། {{name}} ད་ལྟ་མཐོང་ཐུབ།", "Model accepts file inputs": "", "Model accepts image inputs": "དཔེ་དབྱིབས་ཀྱིས་པར་གྱི་ནང་འཇུག་དང་ལེན་བྱེད།", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1312,6 +1338,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API ལྡེ་མིག", + "Month": "", "Monthly": "", "More": "མང་བ།", "More Concise": "", @@ -1330,6 +1357,7 @@ "New Automation": "", "New Button": "", "New Chat": "ཁ་བརྡ་གསར་པ།", + "New Event": "", "New File": "", "New Folder": "ཡིག་སྣོད་གསར་པ།", "New Function": "", @@ -1499,6 +1527,7 @@ "Password": "གསང་གྲངས།", "Passwords do not match.": "", "Paste Large Text as File": "ཡིག་རྐྱང་ཆེན་པོ་ཡིག་ཆ་ལྟར་སྦྱོར་བ།", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF ཡིག་ཆ། (.pdf)", "PDF Extract Images (OCR)": "PDF པར་འདོན་སྤེལ། (OCR)", @@ -1606,6 +1635,7 @@ "Reasoning Effort": "རྒྱུ་མཚན་འདྲེན་པའི་འབད་བརྩོན།", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "སྐད་སྒྲ་ཕབ་པ།", "Redirecting you to Open WebUI Community": "ཁྱེད་ Open WebUI སྤྱི་ཚོགས་ལ་ཁ་ཕྱོགས་སྒྱུར་བཞིན་པ།", @@ -1629,6 +1659,7 @@ "Relevance": "འབྲེལ་ཡོད་རང་བཞིན།", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "འདོར་བ།", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1647,6 +1678,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "བསྐྱར་སྒྲིག་དཔེ་དབྱིབས།", "Reset": "སླར་སྒྲིག", @@ -1873,7 +1905,10 @@ "Start a new conversation": "", "Start of the channel": "རྒྱས་ལམ་འགོ་རིམ་", "Start Tag": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1986,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "འདིས་ {{NAME}} དང་ དེའི་ནང་དོན་ཡོངས་རྫོགས་ བསུབ་ངེས།", "This will delete all models including custom models": "འདིས་སྲོལ་བཟོས་དཔེ་དབྱིབས་ཚུད་པའི་དཔེ་དབྱིབས་ཡོངས་རྫོགས་བསུབ་ངེས།", "This will delete all models including custom models and cannot be undone.": "འདིས་སྲོལ་བཟོས་དཔེ་དབྱིབས་ཚུད་པའི་དཔེ་དབྱིབས་ཡོངས་རྫོགས་བསུབ་ངེས་པ་དང་ཕྱིར་ལྡོག་བྱེད་མི་ཐུབ།", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "འདིས་ཤེས་བྱའི་རྟེན་གཞི་སླར་སྒྲིག་བྱས་ནས་ཡིག་ཆ་ཡོངས་རྫོགས་མཉམ་སྡེབ་བྱེད་ངེས། ཁྱེད་མུ་མཐུད་འདོད་ཡོད་དམ།", "Thorough explanation": "འགྲེལ་བཤད་ཞིབ་ཚགས།", "Thought": "", @@ -2005,6 +2041,7 @@ "Title cannot be an empty string.": "ཁ་བྱང་ཡིག་ཕྲེང་སྟོང་པ་ཡིན་མི་ཆོག", "Title Generation": "ཁ་བྱང་བཟོ་སྐྲུན།", "Title Generation Prompt": "ཁ་བྱང་བཟོ་སྐྲུན་གྱི་འགུལ་སློང་།", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "ཕབ་ལེན་གྱི་ཆེད་དུ་ཡོད་པའི་དཔེ་དབྱིབས་ཀྱི་མིང་ལ་འཛུལ་སྤྱོད་བྱེད་པར།:", "To access the GGUF models available for downloading,": "ཕབ་ལེན་གྱི་ཆེད་དུ་ཡོད་པའི་ GGUF དཔེ་དབྱིབས་ལ་འཛུལ་སྤྱོད་བྱེད་པར།:", @@ -2071,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "གསང་བ་གྲོལ་བ།", "Unpin": "ཕྱིར་འདོན།", + "Unpin from Sidebar": "", "Unravel secrets": "གསང་བ་གྲོལ་བ།", "Unshare Chat": "", "Unsupported file type.": "", @@ -2175,6 +2213,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI ཡིས་ \"{{url}}/api/chat\" ལ་རེ་ཞུ་གཏོང་ངེས།", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI ཡིས་ \"{{url}}/chat/completions\" ལ་རེ་ཞུ་གཏོང་ངེས།", + "Week": "", "Weekly": "", "What are you trying to achieve?": "ཁྱེད་ཀྱིས་ཅི་ཞིག་འགྲུབ་ཐབས་བྱེད་བཞིན་ཡོད།", "What are you working on?": "ཁྱེད་ཀྱིས་ཅི་ཞིག་ལས་ཀ་བྱེད་བཞིན་ཡོད།", @@ -2182,6 +2221,7 @@ "What is shared:": "", "What's New in": "གསར་པ་ཅི་ཡོད།", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "སྒུལ་བསྐྱོད་བྱས་ཚེ། དཔེ་དབྱིབས་ཀྱིས་ཁ་བརྡའི་འཕྲིན་རེ་རེར་དུས་ཐོག་ཏུ་ལན་འདེབས་བྱེད་ངེས། བེད་སྤྱོད་མཁན་གྱིས་འཕྲིན་བཏང་མ་ཐག་ལན་ཞིག་བཟོ་ངེས། མ་དཔེ་འདི་ཐད་གཏོང་ཁ་བརྡའི་བཀོལ་ཆས་ལ་ཕན་ཐོགས་ཡོད། འོན་ཀྱང་དེས་མཁྲེགས་ཆས་དལ་བའི་སྟེང་ལས་ཆོད་ལ་ཤུགས་རྐྱེན་ཐེབས་སྲིད།", "wherever you are": "ཁྱེད་གང་དུ་ཡོད་ཀྱང་།", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/bs-BA/translation.json b/src/lib/i18n/locales/bs-BA/translation.json index 223a0ff884..d28abefd59 100644 --- a/src/lib/i18n/locales/bs-BA/translation.json +++ b/src/lib/i18n/locales/bs-BA/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Razgovori korisnika {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Backend je potreban", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -48,6 +53,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "Račun", "Account Activation Pending": "", @@ -73,9 +79,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Dodaj datoteke", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Dodaj memoriju", @@ -111,6 +119,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Svi modeli su uspjesno izbrisani", @@ -199,6 +208,7 @@ "Ask a question": "Pitaj pitanje", "Assistant": "Asistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "Prikazi znanje", @@ -273,6 +283,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "Poziv", "Call feature is not supported when using Web STT engine": "Značajka poziva nije podržana kada se koristi Web STT mehanizam", "Camera": "Kamera", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "Konekcija nije uspjela", + "Connection lost. Reconnecting...": "", "Connection successful": "Konekcija uspjesna", "Connection Type": "Tip Konekcije", "Connections": "Povezivanja", @@ -440,6 +453,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Kopiraj vezu", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -520,8 +534,11 @@ "Delete All Chats": "Izbriši sve razgovore", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Izbriši razgovor", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Neuspješno stvaranje API ključa.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Slušam...", "Live": "", "Llama.cpp": "", @@ -1207,6 +1230,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1274,6 +1298,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "Model '{{modelName}}' je uspješno preuzet.", "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' je već u redu za preuzimanje.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Model {{modelName}} ne čita vizualne impute", "Model {{name}} is now {{status}}": "Model {{name}} sada je {{status}}", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1314,6 +1340,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Više", "More Concise": "", @@ -1332,6 +1359,7 @@ "New Automation": "", "New Button": "", "New Chat": "Novi razgovor", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1501,6 +1529,7 @@ "Password": "Lozinka", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF dokument (.pdf)", "PDF Extract Images (OCR)": "PDF izdvajanje slika (OCR)", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Snimanje glasa", "Redirecting you to Open WebUI Community": "Preusmjeravanje na OpenWebUI zajednicu", @@ -1631,6 +1661,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Ukloni", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1649,6 +1680,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Model za ponovno rangiranje", "Reset": "", @@ -1877,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "Početak kanala", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "Detaljno objašnjenje", "Thought": "", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "Naslov ne može biti prazni niz.", "Title Generation": "", "Title Generation Prompt": "Prompt za generiranje naslova", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Za pristup dostupnim nazivima modela za preuzimanje,", "To access the GGUF models available for downloading,": "Za pristup GGUF modelima dostupnim za preuzimanje,", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2179,6 +2219,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2186,6 +2227,7 @@ "What is shared:": "", "What's New in": "Što je novo u", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/ca-ES/translation.json b/src/lib/i18n/locales/ca-ES/translation.json index fd49c6ae07..a3793e5e42 100644 --- a/src/lib/i18n/locales/ca-ES/translation.json +++ b/src/lib/i18n/locales/ca-ES/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Els xats de {{user}}", "{{webUIName}} Backend Required": "El Backend de {{webUIName}} és necessari", "*Prompt node ID(s) are required for image generation": "*Els identificadors de nodes d'indicacions són necessaris per a la generació d'imatges", + "1 hour before": "", "1 Source": "1 font", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1m_time_ago", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Un canal de col·laboració on la gent s'uneix com a membres", "A discussion channel where access is controlled by groups and permissions": "Un canal de discussió on l'accés està controlat per grups i permisos", "A new version (v{{LATEST_VERSION}}) is now available.": "Hi ha una nova versió disponible (v{{LATEST_VERSION}}).", @@ -48,6 +53,7 @@ "Access Control": "Control d'accés", "Access Grants": "Assignacions d'accés", "Access List": "Llista d'accés", + "Access updated": "", "Accessible to all users": "Accessible a tots els usuaris", "Account": "Compte", "Account Activation Pending": "Activació del compte pendent", @@ -73,9 +79,11 @@ "Add content here": "Afegir contingut aquí", "Add Custom Parameter": "Afegir paràmetre personalitzat", "Add Custom Prompt": "Afegir indicació personalitzada", + "Add description": "", "Add Details": "Afegir detalls", "Add Files": "Afegir arxius", "Add Image": "Afegir imatge", + "Add location": "", "Add Member": "Afegir membre", "Add Members": "Afegir membres", "Add Memory": "Afegir memòria", @@ -111,6 +119,7 @@ "AI": "IA", "All": "Tots", "All chats have been unarchived.": "Tots els xats han estat desarxivats.", + "All day": "", "All models are now hidden": "Tots els models estan amagats, ara", "All models are now visible": "Tots els models són visibles, ara", "All models deleted successfully": "Tots els models s'han eliminat correctament", @@ -199,6 +208,7 @@ "Ask a question": "Fer una pregunta", "Assistant": "Assistent", "Async Embedding Processing": "Procés d'incrustat asíncron", + "At time of event": "", "Attach File From Knowledge": "Adjuntar arxiu del coneixement", "Attach Files": "Adjuntar arxius", "Attach Knowledge": "Adjuntar coneixement", @@ -273,6 +283,8 @@ "Bypass Web Loader": "Ometre el càrregador web", "Cache Base Model List": "Llista de models base en memòria cau", "Calendar": "Calendari", + "Calendar deleted": "", + "Calendars": "", "Call": "Trucada", "Call feature is not supported when using Web STT engine": "La funció de trucada no s'admet quan s'utilitza el motor Web STT", "Camera": "Càmera", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Connecta als teus propis servidors d'eines externs compatibles amb OpenAPI", "Connected ({{type}})": "Connectat ({{type}})", "Connection failed": "La connexió ha fallat", + "Connection lost. Reconnecting...": "", "Connection successful": "Connexió correcta", "Connection Type": "Tipus de connexió", "Connections": "Connexions", @@ -440,6 +453,7 @@ "Copy Last Response": "Copiar la darrera resposta", "Copy link": "Copiar l'enllaç", "Copy Link": "Copiar l'enllaç", + "Copy Path": "", "Copy Prompt": "Copiar la indicació", "Copy Share Link": "Copiar l'enllaç de compartició", "Copy to clipboard": "Copiar al porta-retalls", @@ -455,7 +469,7 @@ "Create a new note": "Crear una nova nota", "Create Account": "Crear un compte", "Create Admin Account": "Crear un compte d'Administrador", - "Create and manage scheduled automations": "", + "Create and manage scheduled automations": "Crear i gestionar les automatitzacions programades", "Create Channel": "Crear un canal", "Create Folder": "Crear carpeta", "Create Image": "Crear imatge", @@ -481,7 +495,7 @@ "Custom Gender": "Gènere personalitzat", "Custom Parameter Name": "Nom del paràmetre personalitzat", "Custom Parameter Value": "Valor del paràmetre personalitzat", - "Daily": "", + "Daily": "Cada dia", "Daily Messages": "Missatges diaris", "Danger Zone": "Zona de perill", "Dark": "Fosc", @@ -520,8 +534,11 @@ "Delete All Chats": "Eliminar tots els xats", "Delete all contents inside this folder": "Eliminar tot el contingut d'aquesta carpeta", "Delete automation?": "Eliminar l'automatització", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Eliminar xat", "Delete chat?": "Eliminar el xat?", + "Delete Event": "", "Delete File": "Eliminar el fitxer", "Delete folder?": "Eliminar la carpeta?", "Delete function?": "Eliminar funció?", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Error: Ja existeix un model amb l'ID '{{modelId}}'. Selecciona un ID diferent per continuar.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Error: ID de model no pot ser buit. Entra un ID de model vàlid per continuar.", "Evaluations": "Avaluacions", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Clau API d'EXA", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemple: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exemple: TOTS", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "No s'ha pogut connecta al servidor de terminal {{URL}}", "Failed to copy link": "No s'ha pogut copiar l'enllaç", "Failed to create API Key.": "No s'ha pogut crear la clau API.", + "Failed to delete calendar": "", "Failed to delete note": "No s'ha pogut eliminar la nota", "Failed to download image": "No s'ha pogut descarregar la imatge", "Failed to extract content from the file: {{error}}": "No s'ha pogut extreure el contingut del fitxer: {{error}}", @@ -972,7 +994,7 @@ "Forward": "Endavant", "Forwards system user OAuth access token to authenticate": "Reenvia el testimoni d'accés OAuth de l'usuari del sistema per autenticar-se.", "Forwards system user session credentials to authenticate": "Envia les credencials de l'usuari del sistema per autenticar", - "Fr_day_of_week": "", + "Fr_day_of_week": "Divendres", "Full Context Mode": "Mode de context complert", "Function": "Funció", "Function Calling": "Crida a funcions", @@ -1047,7 +1069,7 @@ "History": "Historial", "Home": "Inici", "Host": "Servidor", - "Hourly": "", + "Hourly": "Cada hora", "Hourly Messages": "Missatges horaris", "How can I help you today?": "Com et puc ajudar avui?", "How would you rate this response?": "Com avaluaries aquesta resposta?", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limita les consultes de cerca simultànies. 0 = il·limitada (per defecte). Estableix-ho a 1 per a l'execució seqüencial (recomanat per a API amb límits de velocitat estrictes com el nivell gratuït de Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limita el nombre de sol·licituds d'incrustació simultànies. Estableix-ho a 0 per a un nombre il·limitat.", "List": "Llista", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Escoltant...", "Live": "Live", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1230,7 @@ "local": "local", "Local": "Local", "Local Task Model": "Model local de tasques", + "Location": "", "Location access not allowed": "Accés a la ubicació no permesa", "Lost": "Perdut", "Low": "Baix", @@ -1270,10 +1294,11 @@ "Mistral OCR": "Mistral OCR", "Mistral OCR API Key required.": "És necessària la clau API de Mistral OCR", "MistralAI": "MistralAI", - "Mo_day_of_week": "", + "Mo_day_of_week": "Dilluns", "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "El model '{{modelName}}' s'ha descarregat correctament.", "Model '{{modelTag}}' is already in queue for downloading.": "El model '{{modelTag}}' ja està en cua per ser descarregat.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "El model {{modelName}} s'ha eliminat correctament", "Model {{modelName}} is not vision capable": "El model {{modelName}} no és capaç de visió", "Model {{name}} is now {{status}}": "El model {{name}} ara és {{status}}", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "El model {{name}} està ara visible", "Model accepts file inputs": "El model accepta entrada de fitxers", "Model accepts image inputs": "El model accepta entrades d'imatge", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "El model pot executar codi i realitzar càlculs", "Model can generate images based on text prompts": "El model pot generar imatges basades en les indicacions de text", "Model can search the web for information": "El model pot cercar informació a la web", @@ -1314,7 +1340,8 @@ "Models Sharing": "Compartir els models", "Mojeek": "Mojeek", "Mojeek Search API Key": "Clau API de Mojeek Search", - "Monthly": "", + "Month": "", + "Monthly": "Cada mes", "More": "Més", "More Concise": "Més precís", "More options": "Més opcions", @@ -1332,6 +1359,7 @@ "New Automation": "Nova automatització", "New Button": "Botó nou", "New Chat": "Nou xat", + "New Event": "", "New File": "Nou arxiu", "New Folder": "Nova carpeta", "New Function": "Nova funció", @@ -1435,7 +1463,7 @@ "Ollama Cloud API Key": "Clau API d'Ollama Cloud", "Ollama Version": "Versió d'Ollama", "On": "Activat", - "Once": "", + "Once": "Una vegada", "OneDrive": "OneDrive", "Only active when \"Paste Large Text as File\" setting is toggled on.": "Només està actiu quan l'opció \"Enganxa text gran com a fitxer\" està activada.", "Only active when the chat input is in focus and an LLM is generating a response.": "Només s'activa quan l'entrada del xat està en focus i un LLM està generant una resposta.", @@ -1501,6 +1529,7 @@ "Password": "Contrasenya", "Passwords do not match.": "Les contrasenyes no coincideixen", "Paste Large Text as File": "Enganxa un text llarg com a fitxer", + "Path copied": "", "Paused": "Pausat", "PDF document (.pdf)": "Document PDF (.pdf)", "PDF Extract Images (OCR)": "Extreu imatges del PDF (OCR)", @@ -1520,7 +1549,7 @@ "Persistent": "Persistent", "Personalization": "Personalització", "Pin": "Fixar", - "Pin to Sidebar": "", + "Pin to Sidebar": "Fixar a la barra lateral", "Pinned": "Fixat", "Pinned Messages": "Missatges fixats", "Pinned Models": "Models fixats", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "Esforç de raonament", "Reasoning Tags": "Etiqueta de raonament", "Recently Used": "Recentment utilitzat", + "Reconnected": "", "Record": "Enregistrar", "Record voice": "Enregistrar la veu", "Redirecting you to Open WebUI Community": "Redirigint-te a la comunitat OpenWebUI", @@ -1631,6 +1661,7 @@ "Relevance": "Rellevància", "Relevance Threshold": "Límit de rellevància", "Remember Dismissal": "Recordar la decisió de refutar", + "Reminder": "", "Remove": "Eliminar", "Remove {{MODELID}} from list.": "Eliminar {{MODELID}} de la llista", "Remove action": "Eliminar l'acció", @@ -1649,6 +1680,7 @@ "Reply to thread...": "Respondra al fil...", "Replying to {{NAME}}": "Responent a {{NAME}}", "required": "necessari", + "Reranking Batch Size": "", "Reranking Engine": "Motor de valoració", "Reranking Model": "Model de reavaluació", "Reset": "Restableix", @@ -1682,7 +1714,7 @@ "Running": "S'està executant", "Running...": "S'està executant...", "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "Executa tasques d'incrustació simultàniament per accelerar el processament. Desactiva-ho si els límits de velocitat es converteixen en un problema.", - "Sa_day_of_week": "", + "Sa_day_of_week": "Dissabte", "Save": "Desar", "Save & Create": "Desar i crear", "Save & Update": "Desar i actualitzar", @@ -1877,7 +1909,12 @@ "Start a new conversation": "Iniciar una nova conversa", "Start of the channel": "Inici del canal", "Start Tag": "Etiqueta d'inici", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Iniciant el kernel...", + "Starting now": "", "State": "Estat", "Status": "Estat", "Status cleared successfully": "S'ha eliminat correctament el teu estat", @@ -1899,7 +1936,7 @@ "STT Model": "Model SST", "STT Settings": "Preferències de STT", "Stylized PDF Export": "Exportació en PDF estilitzat", - "Su_day_of_week": "", + "Su_day_of_week": "Diumenge", "Submit question": "Enviar la pregunta", "Submit suggestion": "Enviar un suggeriment", "Subtitle": "Subtítol", @@ -1945,7 +1982,7 @@ "Text Splitter": "Separador de text", "Text-to-Speech": "Text-a-veu", "Text-to-Speech Engine": "Motor de text a veu", - "Th_day_of_week": "", + "Th_day_of_week": "Dijous", "Thanks for your feedback!": "Gràcies pel teu comentari!", "The Application Account DN you bind with for search": "El DN del compte d'aplicació per realitzar la cerca", "The base to search for users": "La base per cercar usuaris", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Això eliminarà {{NAME}} i tots els continguts.", "This will delete all models including custom models": "Això eliminarà tots els models incloent els personalitzats", "This will delete all models including custom models and cannot be undone.": "Això eliminarà tots els models incloent els personalitzats i no es pot desfer", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Això restablirà la base de coneixement i sincronitzarà tots els fitxers. Vols continuar?", "Thorough explanation": "Explicació en detall", "Thought": "Pensament", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "El títol no pot ser una cadena buida.", "Title Generation": "Generació de títols", "Title Generation Prompt": "Indicació de generació de títol", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Per accedir als noms dels models disponibles per descarregar,", "To access the GGUF models available for downloading,": "Per accedir als models GGUF disponibles per descarregar,", @@ -2059,7 +2098,7 @@ "TTS Model": "Model TTS", "TTS Settings": "Preferències de TTS", "TTS Voice": "Veu TTS", - "Tu_day_of_week": "", + "Tu_day_of_week": "Dimarts", "Type": "Tipus", "Type here...": "Escriu aquí...", "Type Hugging Face Resolve (Download) URL": "Escriu la URL de Resolució (Descàrrega) de Hugging Face", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Es descarrega {{FROM_NOW}}", "Unlock mysteries": "Desbloqueja els misteris", "Unpin": "Alliberar", + "Unpin from Sidebar": "", "Unravel secrets": "Descobreix els secrets", "Unshare Chat": "Deixar de compartir el xat", "Unsupported file type.": "Tipus no suportat", @@ -2162,7 +2202,7 @@ "Warning: Enabling this will allow users to run scheduled prompts automatically.": "Avís: Si actives aquesta opció, els usuaris podran executar sol·licituds programades automàticament.", "Warning: Enabling this will allow users to upload arbitrary code on the server.": "Avís: Habilitar això permetrà als usuaris penjar codi arbitrari al servidor.", "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "Avís: l'execució de Jupyter permet l'execució de codi arbitrari, la qual cosa comporta greus riscos de seguretat; procediu amb extrema precaució.", - "We_day_of_week": "", + "We_day_of_week": "Dimecres", "Web": "Web", "Web API": "Web API", "Web Loader Engine": "Motor de càrrega Web", @@ -2179,13 +2219,15 @@ "WebUI will make requests to \"{{url}}\"": "WebUI farà peticions a \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI farà peticions a \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI farà peticions a \"{{url}}/chat/completions\"", - "Weekly": "", + "Week": "", + "Weekly": "Cada setmana", "What are you trying to achieve?": "Què intentes aconseguir?", "What are you working on?": "En què estàs treballant?", "What is NOT shared:": "Què no es comparteix", "What is shared:": "Què es comparteix", "What's New in": "Què hi ha de nou a", "What's on your mind?": "Què tens en ment?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Quan està activat, el model respondrà a cada missatge de xat en temps real, generant una resposta tan bon punt l'usuari envia un missatge. Aquest mode és útil per a aplicacions de xat en directe, però pot afectar el rendiment en maquinari més lent.", "wherever you are": "allà on estiguis", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Si es pagina la sortida. Cada pàgina estarà separada per una regla horitzontal i un número de pàgina. Per defecte és Fals.", diff --git a/src/lib/i18n/locales/ceb-PH/translation.json b/src/lib/i18n/locales/ceb-PH/translation.json index 34a49f5a86..d1278ac30b 100644 --- a/src/lib/i18n/locales/ceb-PH/translation.json +++ b/src/lib/i18n/locales/ceb-PH/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "", "{{webUIName}} Backend Required": "Backend {{webUIName}} gikinahanglan", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -47,6 +52,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "Account", "Account Activation Pending": "", @@ -72,9 +78,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Idugang ang mga file", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -198,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Mga koneksyon", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -519,8 +533,11 @@ "Delete All Chats": "", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1206,6 +1229,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "Ang modelo'{{modelName}}' malampuson nga na-download.", "Model '{{modelTag}}' is already in queue for downloading.": "Ang modelo'{{modelTag}}' naa na sa pila para ma-download.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "", "Model {{name}} is now {{status}}": "", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "Bag-ong diskusyon", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "Password", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "", "PDF Extract Images (OCR)": "PDF Image Extraction (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Irekord ang tingog", "Redirecting you to Open WebUI Community": "Gi-redirect ka sa komunidad sa OpenWebUI", @@ -1630,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "", "Reset": "", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Sinugdan sa channel", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "", "Title Generation": "", "Title Generation Prompt": "Madasig nga henerasyon sa titulo", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Aron ma-access ang mga ngalan sa modelo nga ma-download,", "To access the GGUF models available for downloading,": "Aron ma-access ang mga modelo sa GGUF nga magamit alang sa pag-download,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "Unsay bag-o sa", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/cs-CZ/translation.json b/src/lib/i18n/locales/cs-CZ/translation.json index 227d6b8a61..a787579837 100644 --- a/src/lib/i18n/locales/cs-CZ/translation.json +++ b/src/lib/i18n/locales/cs-CZ/translation.json @@ -35,8 +35,13 @@ "{{user}}'s Chats": "Konverzace uživatele {{user}}", "{{webUIName}} Backend Required": "Je vyžadován backend {{webUIName}}", "*Prompt node ID(s) are required for image generation": "*Pro generování obrázků jsou vyžadována ID uzlů instrukce", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Nová verze (v{{LATEST_VERSION}}) je nyní k dispozici.", @@ -49,6 +54,7 @@ "Access Control": "Řízení přístupu", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Přístupné pro všechny uživatele", "Account": "Účet", "Account Activation Pending": "Čeká se na aktivaci účtu", @@ -74,9 +80,11 @@ "Add content here": "Zde přidejte obsah", "Add Custom Parameter": "Přidat vlastní parametr", "Add Custom Prompt": "", + "Add description": "", "Add Details": "Přidat podrobnosti", "Add Files": "Přidat soubory", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Přidat vzpomínku", @@ -112,6 +120,7 @@ "AI": "UI", "All": "Vše", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Všechny modely byly úspěšně smazány", @@ -200,6 +209,7 @@ "Ask a question": "Položit otázku", "Assistant": "Asistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "Připojit znalosti", @@ -274,6 +284,8 @@ "Bypass Web Loader": "Obejít webový zavaděč", "Cache Base Model List": "Ukládat seznam základních modelů do mezipaměti", "Calendar": "Kalendář", + "Calendar deleted": "", + "Calendars": "", "Call": "Volání", "Call feature is not supported when using Web STT engine": "Funkce volání není podporována při použití webového STT jádra.", "Camera": "Kamera", @@ -410,6 +422,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Připojte se k vlastním externím serverům nástrojů kompatibilním s OpenAPI.", "Connected ({{type}})": "", "Connection failed": "Připojení se nezdařilo", + "Connection lost. Reconnecting...": "", "Connection successful": "Připojení úspěšné", "Connection Type": "Typ připojení", "Connections": "Připojení", @@ -441,6 +454,7 @@ "Copy Last Response": "", "Copy link": "Kopírovat odkaz", "Copy Link": "Kopírovat odkaz", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Kopírovat do schránky", @@ -521,8 +535,11 @@ "Delete All Chats": "Smazat všechny konverzace", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Smazat konverzaci", "Delete chat?": "Smazat konverzaci?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Smazat složku?", "Delete function?": "Smazat funkci?", @@ -829,6 +846,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Chyba: Model s ID '{{modelId}}' již existuje. Pro pokračování prosím zvolte jiné ID.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Chyba: ID modelu nemůže být prázdné. Pro pokračování prosím zadejte platné ID.", "Evaluations": "Hodnocení", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "API klíč pro Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Příklad: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Příklad: VŠE", @@ -877,6 +898,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Nepodařilo se zkopírovat odkaz", "Failed to create API Key.": "Nepodařilo se vytvořit API klíč.", + "Failed to delete calendar": "", "Failed to delete note": "Nepodařilo se smazat poznámku", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Nepodařilo se extrahovat obsah ze souboru: {{error}}", @@ -1198,6 +1220,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Poslouchám...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1231,7 @@ "local": "", "Local": "Lokální", "Local Task Model": "Lokální model pro úkoly", + "Location": "", "Location access not allowed": "Přístup k poloze nebyl povolen", "Lost": "Prohrál", "Low": "Nízká", @@ -1275,6 +1299,7 @@ "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "Model '{{modelName}}' byl úspěšně stažen.", "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' je již ve frontě na stažení.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Model {{modelName}} nemá schopnost zpracování obrazu.", "Model {{name}} is now {{status}}": "Model {{name}} je nyní {{status}}.", @@ -1282,6 +1307,7 @@ "Model {{name}} is now visible": "Model {{name}} je nyní viditelný", "Model accepts file inputs": "Model přijímá souborové vstupy", "Model accepts image inputs": "Model přijímá obrazové vstupy", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Model umí spouštět kód a provádět výpočty", "Model can generate images based on text prompts": "Model umí generovat obrázky na základě textových instrukcí", "Model can search the web for information": "Model umí vyhledávat informace na webu", @@ -1315,6 +1341,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "API klíč pro Mojeek Search", + "Month": "", "Monthly": "", "More": "Více", "More Concise": "Stručnější", @@ -1333,6 +1360,7 @@ "New Automation": "", "New Button": "Nové tlačítko", "New Chat": "Nová konverzace", + "New Event": "", "New File": "", "New Folder": "Nová složka", "New Function": "Nová funkce", @@ -1502,6 +1530,7 @@ "Password": "Heslo", "Passwords do not match.": "Hesla se neshodují.", "Paste Large Text as File": "Vložit velký text jako soubor", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Dokument PDF (.pdf)", "PDF Extract Images (OCR)": "Extrahovat obrázky z PDF (OCR)", @@ -1609,6 +1638,7 @@ "Reasoning Effort": "reasoning effort", "Reasoning Tags": "reasoning tags", "Recently Used": "", + "Reconnected": "", "Record": "Nahrát", "Record voice": "Nahrát hlas", "Redirecting you to Open WebUI Community": "Přesměrovávám vás do komunity Open WebUI", @@ -1632,6 +1662,7 @@ "Relevance": "Relevance", "Relevance Threshold": "Prahová hodnota relevance", "Remember Dismissal": "Pamatovat si zavření", + "Reminder": "", "Remove": "Odebrat", "Remove {{MODELID}} from list.": "Odebrat {{MODELID}} ze seznamu.", "Remove action": "", @@ -1650,6 +1681,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "Jádro pro přehodnocení", "Reranking Model": "Model pro přehodnocení", "Reset": "Resetovat", @@ -1879,7 +1911,13 @@ "Start a new conversation": "", "Start of the channel": "Začátek kanálu", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1992,6 +2030,7 @@ "This will delete {{NAME}} and all its contents.": "Tím se smaže {{NAME}} a veškerý jeho obsah.", "This will delete all models including custom models": "Tím se smažou všechny modely včetně vlastních modelů", "This will delete all models including custom models and cannot be undone.": "Tím se smažou všechny modely včetně vlastních a tuto akci nelze vrátit zpět.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Tím se resetuje znalostní báze a synchronizují se všechny soubory. Přejete si pokračovat?", "Thorough explanation": "Důkladné vysvětlení", "Thought": "", @@ -2011,6 +2050,7 @@ "Title cannot be an empty string.": "Název nemůže být prázdný řetězec.", "Title Generation": "Generování názvu", "Title Generation Prompt": "Instrukce pro generování názvu", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Pro přístup k dostupným názvům modelů ke stažení,", "To access the GGUF models available for downloading,": "Pro přístup k modelům GGUF dostupným ke stažení,", @@ -2077,6 +2117,7 @@ "Unloads {{FROM_NOW}}": "Uvolní se {{FROM_NOW}}", "Unlock mysteries": "Odhalte záhady", "Unpin": "Odepnout", + "Unpin from Sidebar": "", "Unravel secrets": "Rozplétejte tajemství", "Unshare Chat": "", "Unsupported file type.": "Nepodporovaný typ souboru.", @@ -2181,6 +2222,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI bude odesílat požadavky na \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI bude odesílat požadavky na \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI bude odesílat požadavky na \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Čeho se snažíte dosáhnout?", "What are you working on?": "Na čem pracujete?", @@ -2188,6 +2230,7 @@ "What is shared:": "", "What's New in": "Co je nového v", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Když je povoleno, model bude odpovídat na každou zprávu v konverzaci v reálném čase a generovat odpověď, jakmile uživatel odešle zprávu. Tento režim je užitečný pro aplikace s živou konverzací, ale může ovlivnit výkon na pomalejším hardwaru.", "wherever you are": "ať jste kdekoli", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Zda stránkovat výstup. Každá stránka bude oddělena vodorovnou čarou a číslem stránky. Výchozí hodnota je False.", diff --git a/src/lib/i18n/locales/da-DK/translation.json b/src/lib/i18n/locales/da-DK/translation.json index 5e0e4af930..cde38de62f 100644 --- a/src/lib/i18n/locales/da-DK/translation.json +++ b/src/lib/i18n/locales/da-DK/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}s chats", "{{webUIName}} Backend Required": "{{webUIName}} Backend kræves", "*Prompt node ID(s) are required for image generation": "*Prompt node ID(s) er påkrævet for at kunne generere billeder", + "1 hour before": "", "1 Source": "1 kilde", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "En samarbejdskanal hvor folk tilmelder sig som medlemmer", "A discussion channel where access is controlled by groups and permissions": "En diskussionskanal hvor adgang styres af grupper og tilladelser", "A new version (v{{LATEST_VERSION}}) is now available.": "En ny version (v{{LATEST_VERSION}}) er nu tilgængelig.", @@ -47,6 +52,7 @@ "Access Control": "Adgangskontrol", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Tilgængelig for alle brugere", "Account": "Profil", "Account Activation Pending": "Aktivering af profil afventer", @@ -72,9 +78,11 @@ "Add content here": "Tilføj indhold her", "Add Custom Parameter": "Tilføj brugerdefineret parameter", "Add Custom Prompt": "Tilføj brugerdefineret prompt", + "Add description": "", "Add Details": "Tilføj detaljer", "Add Files": "Tilføj filer", "Add Image": "", + "Add location": "", "Add Member": "Tilføj medlem", "Add Members": "Tilføj medlemmer", "Add Memory": "Tilføj hukommelse", @@ -110,6 +118,7 @@ "AI": "AI", "All": "Alle", "All chats have been unarchived.": "Alle chatte er blevet aktive", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Alle modeller slettet uden fejl", @@ -198,6 +207,7 @@ "Ask a question": "Stil et spørgsmål", "Assistant": "Assistent", "Async Embedding Processing": "Asynkron embedding processering", + "At time of event": "", "Attach File From Knowledge": "Vedhæft fil fra viden", "Attach Files": "", "Attach Knowledge": "Vedhæft viden", @@ -272,6 +282,8 @@ "Bypass Web Loader": "Omgå Web Loader", "Cache Base Model List": "Cache Base Model List", "Calendar": "Kalender", + "Calendar deleted": "", + "Calendars": "", "Call": "Opkald", "Call feature is not supported when using Web STT engine": "Opkaldsfunktion er ikke understøttet for Web STT engine", "Camera": "Kamera", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Opret forbindelse til dine egne OpenAPI kompatible eksterne værktøjsservere.", "Connected ({{type}})": "", "Connection failed": "Forbindelse mislykkedes", + "Connection lost. Reconnecting...": "", "Connection successful": "Forbindelse lykkedes", "Connection Type": "Forbindelsestype", "Connections": "Forbindelser", @@ -439,6 +452,7 @@ "Copy Last Response": "Kopier sidste svar", "Copy link": "Kopier link", "Copy Link": "Kopier link", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Kopier til udklipsholder", @@ -519,8 +533,11 @@ "Delete All Chats": "Slet alle chats", "Delete all contents inside this folder": "Slet alt indhold i denne mappe", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Slet chat", "Delete chat?": "Slet chat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Slet mappe?", "Delete function?": "Slet funktion?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Fejl: En model med ID '{{modelId}}' eksisterer allerede. Vælg venligst et andet ID for at fortsætte.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Fejl: Model ID kan ikke være tomt. Indtast venligst et gyldigt ID for at fortsætte.", "Evaluations": "Evalueringer", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API-nøgle", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Eksempel: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Eksempel: ALL", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Kunne ikke kopiere link", "Failed to create API Key.": "Kunne ikke oprette API-nøgle.", + "Failed to delete calendar": "", "Failed to delete note": "Kunne ikke slette note", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Kunne ikke udtrække indhold fra filen: {{error}}", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Lytter...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "lokal", "Local": "Lokal", "Local Task Model": "Lokal opgavemodel", + "Location": "", "Location access not allowed": "Adgang til placering ikke tilladt", "Lost": "Tabt", "Low": "Lav", @@ -1273,6 +1297,7 @@ "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "Model '{{modelName}}' er blevet downloadet.", "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' er allerede i kø til download.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Model {{modelName}} understøtter ikke billeder", "Model {{name}} is now {{status}}": "Model {{name}} er nu {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "Model {{name}} er nu synlig", "Model accepts file inputs": "Model accepterer fil inputs", "Model accepts image inputs": "Model accepterer billedinput", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Model kan udføre kode og foretage beregninger", "Model can generate images based on text prompts": "Model kan generere billeder baseret på tekstprompts", "Model can search the web for information": "Model kan søge på internettet efter information", @@ -1313,6 +1339,7 @@ "Models Sharing": "Modeldeling", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API nøgle", + "Month": "", "Monthly": "", "More": "Mere", "More Concise": "Mere kortfattet", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "Ny knap", "New Chat": "Ny chat", + "New Event": "", "New File": "", "New Folder": "Ny mappe", "New Function": "Ny funktion", @@ -1500,6 +1528,7 @@ "Password": "Adgangskode", "Passwords do not match.": "Passwords stemmer ikke overens.", "Paste Large Text as File": "Indsæt store tekster som fil", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF-dokument (.pdf)", "PDF Extract Images (OCR)": "Udtræk billeder fra PDF (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Ræsonnements indsats", "Reasoning Tags": "Ræsonneringstags", "Recently Used": "", + "Reconnected": "", "Record": "Optag", "Record voice": "Optag stemme", "Redirecting you to Open WebUI Community": "Omdirigerer dig til OpenWebUI Community", @@ -1630,6 +1660,7 @@ "Relevance": "Relevans", "Relevance Threshold": "Relevans tærskel", "Remember Dismissal": "Husk afvisning", + "Reminder": "", "Remove": "Fjern", "Remove {{MODELID}} from list.": "Fjern {{MODELID}} fra listen.", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "Svar på tråd...", "Replying to {{NAME}}": "Svarer {{NAME}}", "required": "påkrævet", + "Reranking Batch Size": "", "Reranking Engine": "Omarrangerings engine", "Reranking Model": "Omarrangeringsmodel", "Reset": "Nulstil", @@ -1875,7 +1907,11 @@ "Start a new conversation": "Start en ny samtale", "Start of the channel": "Kanalens start", "Start Tag": "Start tag", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "Status", "Status cleared successfully": "Status slettet", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Dette vil slette {{NAME}} og alt dens indhold.", "This will delete all models including custom models": "Dette vil slette alle modeller, inklusive brugerdefinerede modeller", "This will delete all models including custom models and cannot be undone.": "Dette vil slette alle modeller, inklusive brugerdefinerede modeller og kan ikke fortrydes.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Dette vil nulstille vidensbasen og synkronisere alle filer. Vil du fortsætte?", "Thorough explanation": "Grundig forklaring", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Titel kan ikke være en tom streng.", "Title Generation": "Titel-generation", "Title Generation Prompt": "Prompt til titelgenerering", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "For at få adgang til de tilgængelige modelnavne til download,", "To access the GGUF models available for downloading,": "For at få adgang til de GGUF-modeller, der er tilgængelige til download,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "Aflaster {{FROM_NOW}}", "Unlock mysteries": "Lås op for mysterier", "Unpin": "Frigør", + "Unpin from Sidebar": "", "Unravel secrets": "Afslør hemmeligheder", "Unshare Chat": "", "Unsupported file type.": "Ikke-understøttet filtype.", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI vil lave forespørgsler til \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI vil lave forespørgsler til \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI vil lave forespørgsler til \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Hvad prøver du at opnå?", "What are you working on?": "Hvad arbejder du på?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "Nyheder i", "What's on your mind?": "Hvad har du på hjertet?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Når aktiveret, vil modellen reagere på hver chatbesked i realtid og generere et svar, så snart brugeren sender en besked. Denne tilstand er nyttig til live chat-applikationer, men kan påvirke ydeevnen på langsommere hardware.", "wherever you are": "hvad end du er", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Om outputtet skal pagineres. Hver side vil være adskilt af en vandret streg og sidetal. Standard er False.", diff --git a/src/lib/i18n/locales/de-DE/translation.json b/src/lib/i18n/locales/de-DE/translation.json index 58171851e9..aec1910274 100644 --- a/src/lib/i18n/locales/de-DE/translation.json +++ b/src/lib/i18n/locales/de-DE/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "Chats von {{user}}", "{{webUIName}} Backend Required": "{{webUIName}}-Backend erforderlich", "*Prompt node ID(s) are required for image generation": "*Prompt-Node-ID(s) sind für die Bildgenerierung erforderlich", + "1 hour before": "", "1 Source": "1 Quelle", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "vor 1 Minute", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Ein Kanal zur Zusammenarbeit, dem Mitglieder beitreten können", "A discussion channel where access is controlled by groups and permissions": "Ein Diskussionskanal, dessen Zugriff durch Gruppen und Berechtigungen gesteuert wird", "A new version (v{{LATEST_VERSION}}) is now available.": "Eine neue Version (v{{LATEST_VERSION}}) ist jetzt verfügbar.", @@ -47,6 +52,7 @@ "Access Control": "Zugriffskontrolle", "Access Grants": "Zugriffsrechte", "Access List": "Zugriffsliste", + "Access updated": "", "Accessible to all users": "Für alle Benutzer zugänglich", "Account": "Konto", "Account Activation Pending": "Kontoaktivierung ausstehend", @@ -72,9 +78,11 @@ "Add content here": "Inhalt hier hinzufügen", "Add Custom Parameter": "Benutzerdefinierten Parameter hinzufügen", "Add Custom Prompt": "Benutzerdefinierten Prompt hinzufügen", + "Add description": "", "Add Details": "Details hinzufügen", "Add Files": "Dateien hinzufügen", "Add Image": "Bild hinzufügen", + "Add location": "", "Add Member": "Mitglied hinzufügen", "Add Members": "Mitglieder hinzufügen", "Add Memory": "Erinnerung hinzufügen", @@ -110,6 +118,7 @@ "AI": "KI", "All": "Alle", "All chats have been unarchived.": "Alle Chats wurden aus dem Archiv wiederhergestellt.", + "All day": "", "All models are now hidden": "Alle Modelle sind nun versteckt", "All models are now visible": "Alle Modelle sind nun sichtbar", "All models deleted successfully": "Alle Modelle erfolgreich gelöscht", @@ -198,6 +207,7 @@ "Ask a question": "Stellen Sie eine Frage", "Assistant": "Assistent", "Async Embedding Processing": "Asynchrone Embedding-Verarbeitung", + "At time of event": "", "Attach File From Knowledge": "Datei aus Wissensspeicher anhängen", "Attach Files": "Dateien anhängen", "Attach Knowledge": "Wissen anhängen", @@ -272,6 +282,8 @@ "Bypass Web Loader": "Web-Loader umgehen", "Cache Base Model List": "Basismodell-Liste cachen", "Calendar": "Kalender", + "Calendar deleted": "", + "Calendars": "", "Call": "Anruf", "Call feature is not supported when using Web STT engine": "Die Anruffunktion wird bei Verwendung der Web-STT-Engine nicht unterstützt.", "Camera": "Kamera", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Verbinden Sie Ihre eigenen OpenAPI-kompatiblen externen Tool-Server.", "Connected ({{type}})": "Verbunden ({{type}})", "Connection failed": "Verbindung fehlgeschlagen", + "Connection lost. Reconnecting...": "", "Connection successful": "Verbindung erfolgreich", "Connection Type": "Verbindungstyp", "Connections": "Verbindungen", @@ -439,6 +452,7 @@ "Copy Last Response": "Letzte Antwort kopieren", "Copy link": "Link kopieren", "Copy Link": "Link kopieren", + "Copy Path": "", "Copy Prompt": "Prompt kopieren", "Copy Share Link": "Freigabelink kopieren", "Copy to clipboard": "In Zwischenablage kopieren", @@ -454,7 +468,7 @@ "Create a new note": "Neue Notiz erstellen", "Create Account": "Konto erstellen", "Create Admin Account": "Admin-Konto erstellen", - "Create and manage scheduled automations": "", + "Create and manage scheduled automations": "Erstelle und manage geplante Automatisierungen", "Create Channel": "Kanal erstellen", "Create Folder": "Ordner erstellen", "Create Image": "Bild erstellen", @@ -480,7 +494,7 @@ "Custom Gender": "Benutzerdefiniertes Geschlecht", "Custom Parameter Name": "Name des benutzerdef. Parameters", "Custom Parameter Value": "Wert des benutzerdef. Parameters", - "Daily": "", + "Daily": "Täglich", "Daily Messages": "Tägliche Nachrichten", "Danger Zone": "Gefahrenzone", "Dark": "Dunkel", @@ -519,8 +533,11 @@ "Delete All Chats": "Alle Chats löschen", "Delete all contents inside this folder": "Alle Inhalte in diesem Ordner löschen", "Delete automation?": "Automatisierung löschen?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Chat löschen", "Delete chat?": "Chat löschen?", + "Delete Event": "", "Delete File": "Datei löschen", "Delete folder?": "Ordner löschen?", "Delete function?": "Funktion löschen?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Fehler: Ein Modell mit der ID '{{modelId}}' existiert bereits. Bitte wählen Sie eine andere ID.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Fehler: Die Modell-ID darf nicht leer sein. Bitte geben Sie eine gültige ID ein.", "Evaluations": "Evaluationen", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API-Schlüssel", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Bsp: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Bsp: ALL", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "Fehler beim Verbinden zum Terminal Server {{URL}}", "Failed to copy link": "Link konnte nicht kopiert werden", "Failed to create API Key.": "API-Schlüssel konnte nicht erstellt werden.", + "Failed to delete calendar": "", "Failed to delete note": "Notiz konnte nicht gelöscht werden", "Failed to download image": "Bild konnte nicht heruntergeladen werden", "Failed to extract content from the file: {{error}}": "Inhaltsextraktion fehlgeschlagen: {{error}}", @@ -971,7 +993,7 @@ "Forward": "Weiterleiten", "Forwards system user OAuth access token to authenticate": "Leitet OAuth-Zugriffstoken des Systembenutzers zur Authentifizierung weiter", "Forwards system user session credentials to authenticate": "Leitet Sitzungsdaten des Systembenutzers zur Authentifizierung weiter", - "Fr_day_of_week": "", + "Fr_day_of_week": "Fr", "Full Context Mode": "Vollkontext-Modus", "Function": "Funktion", "Function Calling": "Funktionsaufruf", @@ -1046,7 +1068,7 @@ "History": "History", "Home": "Startseite", "Host": "Host", - "Hourly": "", + "Hourly": "Stündlich", "Hourly Messages": "Stündliche Nachrichten", "How can I help you today?": "Wie kann ich Ihnen heute helfen?", "How would you rate this response?": "Wie bewerten Sie diese Antwort?", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Gleichzeitige Suchanfragen begrenzen. 0 = unbegrenzt (Standard). Auf 1 setzen für sequentielle Ausführung (empfohlen für APIs mit strengen Ratenbegrenzungen wie dem kostenlosen Brave-Tarif).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limitiert die Anzahl gleichzeitiger embedding Anfragen. Auf 0 setzen für unlimitiert.", "List": "Liste", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Höre zu...", "Live": "Live", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "lokal", "Local": "Lokal", "Local Task Model": "Lokales Aufgabenmodell", + "Location": "", "Location access not allowed": "Standortzugriff nicht erlaubt", "Lost": "Verloren", "Low": "Niedrig", @@ -1269,10 +1293,11 @@ "Mistral OCR": "Mistral OCR", "Mistral OCR API Key required.": "Mistral-OCR-API-Schlüssel erforderlich.", "MistralAI": "MistralAI", - "Mo_day_of_week": "", + "Mo_day_of_week": "Mo", "Model": "Modell", "Model '{{modelName}}' has been successfully downloaded.": "Modell '{{modelName}}' wurde erfolgreich heruntergeladen.", "Model '{{modelTag}}' is already in queue for downloading.": "Modell '{{modelTag}}' befindet sich bereits in der Warteschlange.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "Modell {{modelName}} erfolgreich gelöscht", "Model {{modelName}} is not vision capable": "Das Modell {{modelName}} unterstützt keine Bilderkennung", "Model {{name}} is now {{status}}": "Modell {{name}} ist jetzt {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "Modell {{name}} ist jetzt sichtbar", "Model accepts file inputs": "Modell akzeptiert Dateieingaben", "Model accepts image inputs": "Modell akzeptiert Bildeingaben", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Modell kann Code ausführen und Berechnungen durchführen", "Model can generate images based on text prompts": "Modell kann Bilder basierend auf Text-Prompts generieren", "Model can search the web for information": "Modell kann das Web nach Informationen durchsuchen", @@ -1313,7 +1339,8 @@ "Models Sharing": "Modelle teilen", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Search API-Schlüssel", - "Monthly": "", + "Month": "", + "Monthly": "Monatlich", "More": "Mehr", "More Concise": "Kürzer", "More options": "Mehr Optionen", @@ -1331,6 +1358,7 @@ "New Automation": "Neue Automatisierung", "New Button": "Neuer Button", "New Chat": "Neuer Chat", + "New Event": "", "New File": "Neue Datei", "New Folder": "Neuer Ordner", "New Function": "Neue Funktion", @@ -1434,7 +1462,7 @@ "Ollama Cloud API Key": "Ollama Cloud API-Schlüssel", "Ollama Version": "Ollama-Version", "On": "Ein", - "Once": "", + "Once": "Einmalig", "OneDrive": "OneDrive", "Only active when \"Paste Large Text as File\" setting is toggled on.": "Nur aktiv, wenn die Einstellung „Großen Text als Datei einfügen“ aktiviert ist.", "Only active when the chat input is in focus and an LLM is generating a response.": "Nur aktiv, wenn das Chat-Eingabefeld fokussiert ist und ein LLM eine Antwort generiert.", @@ -1500,6 +1528,7 @@ "Password": "Passwort", "Passwords do not match.": "Die Passwörter stimmen nicht überein.", "Paste Large Text as File": "Großen Text als Datei einfügen", + "Path copied": "", "Paused": "Pausiert", "PDF document (.pdf)": "PDF-Dokument (.pdf)", "PDF Extract Images (OCR)": "Bilder aus PDFs extrahieren (OCR)", @@ -1519,7 +1548,7 @@ "Persistent": "Persistent", "Personalization": "Personalisierung", "Pin": "Anheften", - "Pin to Sidebar": "", + "Pin to Sidebar": "An Seitenleiste anheften", "Pinned": "Angeheftet", "Pinned Messages": "Angeheftete Nachrichten", "Pinned Models": "Angepinnte Modelle", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Reasoning Effort", "Reasoning Tags": "Reasoning Tags", "Recently Used": "Kürzlich verwendet", + "Reconnected": "", "Record": "Aufnehmen", "Record voice": "Stimme aufnehmen", "Redirecting you to Open WebUI Community": "Sie werden zur Open WebUI Community weitergeleitet", @@ -1630,6 +1660,7 @@ "Relevance": "Relevanz", "Relevance Threshold": "Relevanzschwelle", "Remember Dismissal": "Ausblendung merken", + "Reminder": "", "Remove": "Entfernen", "Remove {{MODELID}} from list.": "{{MODELID}} von der Liste entfernen.", "Remove action": "Action entfernen", @@ -1648,6 +1679,7 @@ "Reply to thread...": "Im Thread antworten...", "Replying to {{NAME}}": "Antwort an {{NAME}}", "required": "erforderlich", + "Reranking Batch Size": "", "Reranking Engine": "Reranking-Engine", "Reranking Model": "Reranking-Modell", "Reset": "Zurücksetzen", @@ -1680,7 +1712,7 @@ "Running": "Läuft", "Running...": "Läuft...", "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "Führt Embedding-Aufgaben parallel aus, um die Verarbeitung zu beschleunigen. Deaktivieren Sie dies, falls Rate-Limits oder Ressourcenprobleme auftreten.", - "Sa_day_of_week": "", + "Sa_day_of_week": "Sa", "Save": "Speichern", "Save & Create": "Speichern & Erstellen", "Save & Update": "Speichern & Aktualisieren", @@ -1875,7 +1907,11 @@ "Start a new conversation": "Neue Unterhaltung beginnen", "Start of the channel": "Beginn des Kanals", "Start Tag": "Start-Tag", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Kernel starten...", + "Starting now": "", "State": "Zustand", "Status": "Status", "Status cleared successfully": "Status erfolgreich gelöscht", @@ -1897,7 +1933,7 @@ "STT Model": "STT-Modell", "STT Settings": "STT-Einstellungen", "Stylized PDF Export": "Stilisierter PDF-Export", - "Su_day_of_week": "", + "Su_day_of_week": "So", "Submit question": "Frage absenden", "Submit suggestion": "Vorschlag absenden", "Subtitle": "Untertitel", @@ -1943,7 +1979,7 @@ "Text Splitter": "Text-Splitter", "Text-to-Speech": "Text-zu-Sprache", "Text-to-Speech Engine": "Text-zu-Sprache-Engine", - "Th_day_of_week": "", + "Th_day_of_week": "Do", "Thanks for your feedback!": "Danke für Ihr Feedback!", "The Application Account DN you bind with for search": "Der Anwendungs-Konto-DN für die Suche", "The base to search for users": "Die Basis, in der nach Benutzern gesucht wird", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Dies löscht {{NAME}} und alle Inhalte.", "This will delete all models including custom models": "Dies löscht alle Modelle, einschließlich benutzerdefinierter Modelle", "This will delete all models including custom models and cannot be undone.": "Dies löscht alle Modelle, einschließlich benutzerdefinierter Modelle, und kann nicht rückgängig gemacht werden.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Dadurch wird der Wissensspeicher zurückgesetzt und alle Dateien werden synchronisiert. Möchten Sie fortfahren?", "Thorough explanation": "Ausführliche Erklärung", "Thought": "Gedanke", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Titel darf nicht leer sein.", "Title Generation": "Titelgenerierung", "Title Generation Prompt": "Titelgenerierungs-Prompt", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Um die verfügbaren Modellnamen für den Download anzuzeigen,", "To access the GGUF models available for downloading,": "Um die verfügbaren GGUF-Modelle für den Download anzuzeigen,", @@ -2057,7 +2095,7 @@ "TTS Model": "TTS-Modell", "TTS Settings": "TTS-Einstellungen", "TTS Voice": "TTS-Stimme", - "Tu_day_of_week": "", + "Tu_day_of_week": "Di", "Type": "Typ", "Type here...": "Hier eingeben...", "Type Hugging Face Resolve (Download) URL": "Hugging Face Resolve (Download) URL eingeben", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "Entlädt {{FROM_NOW}}", "Unlock mysteries": "Geheimnisse entschlüsseln", "Unpin": "Lösen", + "Unpin from Sidebar": "", "Unravel secrets": "Geheimnisse lüften", "Unshare Chat": "Chat-Freigabe entfernen", "Unsupported file type.": "Nicht unterstützter Dateityp.", @@ -2160,7 +2199,7 @@ "Warning: Enabling this will allow users to run scheduled prompts automatically.": "Warnung: Wenn Sie dies aktivieren, können Nutzer geplante Prompts automatisch ausführen.", "Warning: Enabling this will allow users to upload arbitrary code on the server.": "Warnung: Wenn Sie dies aktivieren, können Benutzer beliebigen Code auf den Server hochladen.", "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "Warnung: Die Jupyter-Ausführung ermöglicht beliebige Codeausführung und birgt erhebliche Sicherheitsrisiken – gehen Sie mit äußerster Vorsicht vor.", - "We_day_of_week": "", + "We_day_of_week": "Mi", "Web": "Web", "Web API": "Web-API", "Web Loader Engine": "Web-Loader-Engine", @@ -2177,13 +2216,15 @@ "WebUI will make requests to \"{{url}}\"": "WebUI wird Anfragen an \"{{url}}\" senden", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI wird Anfragen an \"{{url}}/api/chat\" senden", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI wird Anfragen an \"{{url}}/chat/completions\" senden", - "Weekly": "", + "Week": "", + "Weekly": "Wöchentlich", "What are you trying to achieve?": "Was möchten Sie erreichen?", "What are you working on?": "Woran arbeiten Sie?", "What is NOT shared:": "Was NICHT geteilt wird:", "What is shared:": "Was geteilt wird:", "What's New in": "Neuigkeiten in", "What's on your mind?": "Was beschäftigt Sie?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Wenn aktiviert, antwortet das Modell in Echtzeit auf jede Chat-Nachricht. Dieser Modus ist nützlich für Live-Chats, kann jedoch die Leistung auf langsamerer Hardware beeinträchtigen.", "wherever you are": "wo immer Sie sind", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Ob die Ausgabe paginiert werden soll. Jede Seite wird durch eine horizontale Linie und Seitennummer getrennt. Standard ist False.", diff --git a/src/lib/i18n/locales/dg-DG/translation.json b/src/lib/i18n/locales/dg-DG/translation.json index 9f2ad4240f..b4a402abac 100644 --- a/src/lib/i18n/locales/dg-DG/translation.json +++ b/src/lib/i18n/locales/dg-DG/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "", "{{webUIName}} Backend Required": "{{webUIName}} Backend Much Required", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -47,6 +52,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "Account", "Account Activation Pending": "", @@ -72,9 +78,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Add Files", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -198,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Connections", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -519,8 +533,11 @@ "Delete All Chats": "", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1206,6 +1229,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "Model '{{modelName}}' has been successfully downloaded.", "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' is already in queue for downloading.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "", "Model {{name}} is now {{status}}": "", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "New Bark", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "Barkword", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "", "PDF Extract Images (OCR)": "PDF Extract Wowmages (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Record Bark", "Redirecting you to Open WebUI Community": "Redirecting you to Open WebUI Community", @@ -1630,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "", "Reset": "", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Start of channel", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "", "Title Generation": "", "Title Generation Prompt": "Title Generation Prompt very prompt", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "To access the available model names for downloading, much access", "To access the GGUF models available for downloading,": "To access the GGUF models available for downloading, much access", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "What's New in much new", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/el-GR/translation.json b/src/lib/i18n/locales/el-GR/translation.json index 6e347a9e94..22391542aa 100644 --- a/src/lib/i18n/locales/el-GR/translation.json +++ b/src/lib/i18n/locales/el-GR/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "Συνομιλίες του {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Απαιτείται Backend", "*Prompt node ID(s) are required for image generation": "*Τα αναγνωριστικά κόμβου Prompt απαιτούνται για τη δημιουργία εικόνων", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Μια νέα έκδοση (v{{LATEST_VERSION}}) είναι τώρα διαθέσιμη.", @@ -47,6 +52,7 @@ "Access Control": "Έλεγχος Πρόσβασης", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Προσβάσιμο σε όλους τους χρήστες", "Account": "Λογαριασμός", "Account Activation Pending": "Ενεργοποίηση Λογαριασμού Εκκρεμεί", @@ -72,9 +78,11 @@ "Add content here": "Προσθέστε περιεχόμενο εδώ", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Προσθήκη Αρχείων", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Προσθήκη Μνήμης", @@ -110,6 +118,7 @@ "AI": "", "All": "Όλα", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Όλα τα μοντέλα διαγράφηκαν με επιτυχία", @@ -198,6 +207,7 @@ "Ask a question": "Ρωτήστε μια ερώτηση", "Assistant": "Βοηθός", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "Προσθήκη Knowledge", @@ -272,6 +282,8 @@ "Bypass Web Loader": "Παράκαμψη Φορτωτή Διαδικτύου", "Cache Base Model List": "Αποθήκευση Λίστας Βασικών Μοντέλων Στην Κρυφή Μνήμη", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "Κλήση", "Call feature is not supported when using Web STT engine": "Η λειτουργία κλήσης δεν υποστηρίζεται όταν χρησιμοποιείται η μηχανή Web STT", "Camera": "Κάμερα", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Συνδεθείτε στους δικούς σας διακομιστές εξωτερικών εργαλείων συμβατών με OpenAPI.", "Connected ({{type}})": "", "Connection failed": "Σύνδεση απέτυχε", + "Connection lost. Reconnecting...": "", "Connection successful": "Σύνδεση επιτυχής", "Connection Type": "Είδος Σύνδεσης", "Connections": "Συνδέσεις", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "Αντιγραφή συνδέσμου", "Copy Link": "Αντιγραφή Συνδέσμου", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Αντιγραφή στο πρόχειρο", @@ -519,8 +533,11 @@ "Delete All Chats": "Διαγραφή Όλων των Συνομιλιών", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Διαγραφή Συνομιλίας", "Delete chat?": "Διαγραφή συνομιλίας;", + "Delete Event": "", "Delete File": "", "Delete folder?": "Διαγραφή φακέλου;", "Delete function?": "Διαγραφή λειτουργίας;", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Αξιολογήσεις", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "API κλειδί του Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Παράδειγμα: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Παράδειγμα: ALL", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Αποτυχία αντιγραφής συνδέσμου", "Failed to create API Key.": "Αποτυχία δημιουργίας Κλειδιού API.", + "Failed to delete calendar": "", "Failed to delete note": "Αποτυχία διαγραφής σημειώσεως", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Ακούγεται...", "Live": "", "Llama.cpp": "", @@ -1206,6 +1229,7 @@ "local": "", "Local": "Τοπικά", "Local Task Model": "Τοπικό Μοντέλο Εργασιών", + "Location": "", "Location access not allowed": "Η πρόσβαση στην τοποθεσία δεν επιτρέπεται", "Lost": "Χαμένος", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "Μοντέλο", "Model '{{modelName}}' has been successfully downloaded.": "Το μοντέλο '{{modelName}}' κατεβάστηκε με επιτυχία.", "Model '{{modelTag}}' is already in queue for downloading.": "Το μοντέλο '{{modelTag}}' βρίσκεται ήδη στην ουρά για λήψη.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Το μοντέλο {{modelName}} δεν έχει δυνατότητα όρασης", "Model {{name}} is now {{status}}": "Το μοντέλο {{name}} είναι τώρα {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "Το μοντέλο δέχεται αρχεία ως είσοδο", "Model accepts image inputs": "Το μοντέλο δέχεται εικόνες ως είσοδο", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Το μοντέλο μπορεί να εκτελεί κώδικα και υπολογισμούς", "Model can generate images based on text prompts": "Το μοντέλο μπορεί να δημιουργήσει εικόνες βασισμένες σε προτροπές κειμένου", "Model can search the web for information": "Το μοντέλο μπορεί να αναζητήσει πληροφορίες στο διαδίκτυο", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Κλειδί API Mojeek Search", + "Month": "", "Monthly": "", "More": "Περισσότερα", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "Νέα Συνομιλία", + "New Event": "", "New File": "", "New Folder": "Νέος Φάκελος", "New Function": "Νέα Λειτουργία", @@ -1500,6 +1528,7 @@ "Password": "Κωδικός", "Passwords do not match.": "Οι κωδικοί δεν ταιριάζουν", "Paste Large Text as File": "Επικόλληση Μεγάλου Κειμένου ως Αρχείο", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Έγγραφο PDF (.pdf)", "PDF Extract Images (OCR)": "Εξαγωγή Εικόνων PDF (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Εγγραφή φωνής", "Redirecting you to Open WebUI Community": "Μετακατεύθυνση στην Κοινότητα OpenWebUI", @@ -1630,6 +1660,7 @@ "Relevance": "Σχετικότητα", "Relevance Threshold": "Όριο Σχετικότητας", "Remember Dismissal": "Θύμηση Απόρριψης", + "Reminder": "", "Remove": "Αφαίρεση", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "Απάντηση στο νήμα συζήτησης...", "Replying to {{NAME}}": "", "required": "απαιτείται", + "Reranking Batch Size": "", "Reranking Engine": "Μηχανή Επαναταξινόμησης", "Reranking Model": "Μοντέλο Επαναταξινόμησης", "Reset": "Επαναφορά", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Αρχή του καναλιού", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Αυτό θα διαγράψει το {{NAME}} και όλο το περιεχόμενό του.", "This will delete all models including custom models": "Αυτό θα διαγράψει όλα τα μοντέλα, συμπεριλαμβανομένων των προσαρμοσμένων μοντέλων", "This will delete all models including custom models and cannot be undone.": "Αυτό θα διαγράψει όλα τα μοντέλα, συμπεριλαμβανομένων των προσαρμοσμένων μοντέλων και δεν μπορεί να αναιρεθεί.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Αυτό θα επαναφέρει τη βάση γνώσης και θα συγχρονίσει όλα τα αρχεία. Θέλετε να συνεχίσετε;", "Thorough explanation": "Λεπτομερής εξήγηση", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Ο τίτλος δεν μπορεί να είναι κενή συμβολοσειρά.", "Title Generation": "Δημιουργία Τίτλου", "Title Generation Prompt": "Προτροπή Δημιουργίας Τίτλου", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Για να αποκτήσετε πρόσβαση στα διαθέσιμα ονόματα μοντέλων για λήψη,", "To access the GGUF models available for downloading,": "Για να αποκτήσετε πρόσβαση στα μοντέλα GGUF διαθέσιμα για λήψη,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Ξεκλείδωμα μυστηρίων", "Unpin": "Ξεκαρφίτσωμα", + "Unpin from Sidebar": "", "Unravel secrets": "Ξετυλίξτε μυστικά", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "Το WebUI θα κάνει αιτήματα στο \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "Το WebUI θα κάνει αιτήματα στο \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "Το WebUI θα κάνει αιτήματα στο \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Τι προσπαθείτε να πετύχετε?", "What are you working on?": "Τι εργάζεστε;", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "Τι νέο υπάρχει στο", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Όταν ενεργοποιηθεί, το μοντέλο θα ανταποκρίνεται σε κάθε μήνυμα συνομιλίας σε πραγματικό χρόνο, δημιουργώντας μια απάντηση μόλις ο χρήστης στείλει ένα μήνυμα. Αυτή η λειτουργία είναι χρήσιμη για εφαρμογές ζωντανής συνομιλίας, αλλά μπορεί να επηρεάσει την απόδοση σε πιο αργό υλικό.", "wherever you are": "οπουδήποτε βρίσκεστε", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/en-GB/translation.json b/src/lib/i18n/locales/en-GB/translation.json index 28a735ae18..88cfb9a311 100644 --- a/src/lib/i18n/locales/en-GB/translation.json +++ b/src/lib/i18n/locales/en-GB/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "", "{{webUIName}} Backend Required": "", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -47,6 +52,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "", "Account Activation Pending": "", @@ -72,9 +78,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -198,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -519,8 +533,11 @@ "Delete All Chats": "", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1206,6 +1229,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "", "Model '{{modelTag}}' is already in queue for downloading.": "", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "", "Model {{name}} is now {{status}}": "", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "", "PDF Extract Images (OCR)": "", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "", "Redirecting you to Open WebUI Community": "", @@ -1630,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "", "Reset": "", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "", "Title Generation": "", "Title Generation Prompt": "", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "", "To access the GGUF models available for downloading,": "", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/en-US/translation.json b/src/lib/i18n/locales/en-US/translation.json index b9f462c6a9..ad0f42f733 100644 --- a/src/lib/i18n/locales/en-US/translation.json +++ b/src/lib/i18n/locales/en-US/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "", "{{webUIName}} Backend Required": "", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -47,6 +52,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "", "Account Activation Pending": "", @@ -72,9 +78,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -198,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -519,8 +533,11 @@ "Delete All Chats": "", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1206,6 +1229,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "", "Model '{{modelTag}}' is already in queue for downloading.": "", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "", "Model {{name}} is now {{status}}": "", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "", "PDF Extract Images (OCR)": "", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "", "Redirecting you to Open WebUI Community": "", @@ -1630,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "", "Reset": "", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "", "Title Generation": "", "Title Generation Prompt": "", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "", "To access the GGUF models available for downloading,": "", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/es-ES/translation.json b/src/lib/i18n/locales/es-ES/translation.json index 63e98ee49d..2f44afcee4 100644 --- a/src/lib/i18n/locales/es-ES/translation.json +++ b/src/lib/i18n/locales/es-ES/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Chats de {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Servidor Requerido", "*Prompt node ID(s) are required for image generation": "Los ID de nodo son requeridos para la generación de imágenes", + "1 hour before": "", "1 Source": "1 Fuente", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "hace_1m", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Canal colaborativo donde la gente se une como miembro", "A discussion channel where access is controlled by groups and permissions": "Un canal de discusión con el acceso controlado mediante grupos y permisos", "A new version (v{{LATEST_VERSION}}) is now available.": "Nueva versión (v{{LATEST_VERSION}}) disponible.", @@ -48,6 +53,7 @@ "Access Control": "Control de Permisos", "Access Grants": "Permisos Otorgados", "Access List": "Lista de Permisos", + "Access updated": "", "Accessible to all users": "Accesible para todos los usuarios", "Account": "Cuenta", "Account Activation Pending": "Activación de cuenta Pendiente", @@ -73,9 +79,11 @@ "Add content here": "Añadir contenido aquí", "Add Custom Parameter": "Añadir Parámetro Personalizado", "Add Custom Prompt": "Añadir Indicador Personalizado", + "Add description": "", "Add Details": "Añadir Detalles", "Add Files": "Añadir Archivos", "Add Image": "Añadir Imagen", + "Add location": "", "Add Member": "Añadir Miembro", "Add Members": "Añadir Miembros", "Add Memory": "Añadir Memoria", @@ -111,6 +119,7 @@ "AI": "IA", "All": "Todos", "All chats have been unarchived.": "Todos los chats han sido desarchivados", + "All day": "", "All models are now hidden": "Todos los modelos están ahora ocultos", "All models are now visible": "Todos los modelos están ahora visibles", "All models deleted successfully": "Todos los modelos se han borrados correctamente", @@ -199,6 +208,7 @@ "Ask a question": "Haz una pregunta", "Assistant": "Asistente", "Async Embedding Processing": "Procesado Asíncrono al Incrustrar", + "At time of event": "", "Attach File From Knowledge": "Adjuntar Archivo desde Conocimiento", "Attach Files": "Adjuntar Archivos", "Attach Knowledge": "Adjuntar Conocimiento", @@ -273,6 +283,8 @@ "Bypass Web Loader": "Desactivar Cargar de Web", "Cache Base Model List": "Cachear Lista de Cache Modelos", "Calendar": "Calendario", + "Calendar deleted": "", + "Calendars": "", "Call": "Llamada", "Call feature is not supported when using Web STT engine": "La funcionalidad de Llamada no está soportada cuando se usa el motor Web STT", "Camera": "Cámara", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Conectar a tus propios endpoints externos de herramientas compatibles con OpenAPI.", "Connected ({{type}})": "Connectado ({{type}})", "Connection failed": "Conexión fallida", + "Connection lost. Reconnecting...": "", "Connection successful": "Conexión realizada", "Connection Type": "Tipo de Conexión", "Connections": "Conexiones", @@ -440,6 +453,7 @@ "Copy Last Response": "Copiar la última Respuesta", "Copy link": "Copiar Enlace", "Copy Link": "Copiar enlace", + "Copy Path": "", "Copy Prompt": "Copiar Indicador", "Copy Share Link": "Copiar Enlace Compartido", "Copy to clipboard": "Copia a portapapeles", @@ -455,7 +469,7 @@ "Create a new note": "Crea una nueva nota", "Create Account": "Crear Cuenta", "Create Admin Account": "Crear Cuenta Administrativa", - "Create and manage scheduled automations": "", + "Create and manage scheduled automations": "Crear y gestionar automatizaciones programadas", "Create Channel": "Crear Canal", "Create Folder": "Crear Carpeta", "Create Image": "Crear Imagen", @@ -481,7 +495,7 @@ "Custom Gender": "Género Personalizado", "Custom Parameter Name": "Nombre del Parámetro Personalizado", "Custom Parameter Value": "Valor del Parámetro Personalizado", - "Daily": "", + "Daily": "Diario", "Daily Messages": "Mensajes Diarios", "Danger Zone": "Zona Peligrosa", "Dark": "Oscuro", @@ -520,8 +534,11 @@ "Delete All Chats": "Borrar todos los chats", "Delete all contents inside this folder": "Borrar todo el contenido de esta carpeta", "Delete automation?": "¿Borrar automatización?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Borrar Chat", "Delete chat?": "¿Borrar el chat?", + "Delete Event": "", "Delete File": "Borrar Fichero", "Delete folder?": "¿Borrar carpeta?", "Delete function?": "Borrar la función?", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Error: Ya existe un modelo con el ID '{{modelId}}'. Seleccione otro ID para continuar.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Error: El ID del modelo no puede estar vacío. Ingrese un ID válido para continuar.", "Evaluations": "Evaluaciones", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Clave API de Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Ejemplo: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Ejemplo: TODOS", @@ -849,8 +870,8 @@ "Export": "Exportar", "Export All Archived Chats": "Exportar Todos los Chats Archivados", "Export All Chats (All Users)": "Exportar Todos los Chats (Todos los Usuarios)", - "Export as CSV": "", - "Export as JSON": "", + "Export as CSV": "Exportar como CSV", + "Export as JSON": "Exportar como JSON", "Export chat (.json)": "Exportar chat (.json)", "Export Chats": "Exportar Chats", "Export Config": "Exportar Config", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "Fallo al conectar al servidor de terminal: {{URL}}", "Failed to copy link": "Fallo al copiar enlace", "Failed to create API Key.": "Fallo al crear la Clave API.", + "Failed to delete calendar": "", "Failed to delete note": "Fallo al eliminar nota", "Failed to download image": "Fallo al descargar imagen", "Failed to extract content from the file: {{error}}": "Fallo al extraer el contenido del archivo: {{error}}", @@ -972,7 +994,7 @@ "Forward": "Reenviar", "Forwards system user OAuth access token to authenticate": "Reenvía el token de acceso OAuth del usuario del sistema para autenticarse", "Forwards system user session credentials to authenticate": "Reenvío de las credenciales de la sesión del usuario del sistema para autenticación", - "Fr_day_of_week": "", + "Fr_day_of_week": "los viernes", "Full Context Mode": "Modo Contexto Completo", "Function": "Función", "Function Calling": "Modo de Llamada a Funciones (Herramientas)", @@ -1047,7 +1069,7 @@ "History": "Historial", "Home": "Inicio", "Host": "Host", - "Hourly": "", + "Hourly": "Horario", "Hourly Messages": "Mensajes por Hora", "How can I help you today?": "¿Cómo puedo ayudarte hoy?", "How would you rate this response?": "¿Cómo calificarías esta respuesta?", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limitar consultas de búsqueda simultáneas. 0 = ilimitado (predeterminado). Establécerlo en 1 para ejecución secuencial (recomendado para API con límites de velocidad estrictos, como la versión gratuita de Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limita el número de peticiones concurrentes al incrustrar. Ajusta a 0 para ilimitadas", "List": "Lista", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Escuchando...", "Live": "En Directo", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1230,7 @@ "local": "local", "Local": "Local", "Local Task Model": "Modelo Local para Tarea", + "Location": "", "Location access not allowed": "Acceso a la Ubicación no permitido", "Lost": "Perdido", "Low": "Bajo", @@ -1270,10 +1294,11 @@ "Mistral OCR": "OCR Mistral", "Mistral OCR API Key required.": "Clave API de Mistral OCR requerida", "MistralAI": "MistralAI", - "Mo_day_of_week": "", + "Mo_day_of_week": "los lunes", "Model": "Modelo", "Model '{{modelName}}' has been successfully downloaded.": "Modelo '{{modelName}}' se ha descargado correctamente.", "Model '{{modelTag}}' is already in queue for downloading.": "Modelo '{{modelTag}}' ya está en cola para descargar.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "Modelo {{modelName}} borrado correctamente", "Model {{modelName}} is not vision capable": "Modelo {{modelName}} no esta capacitado para visión", "Model {{name}} is now {{status}}": "Modelo {{name}} está ahora {{status}}", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "Modelo {{name}} está ahora visible", "Model accepts file inputs": "Modelo acepta entrada de archivos", "Model accepts image inputs": "Modelo acepta entrada de imagenes", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Modelo puedo ejecutar código y realizar cálculos", "Model can generate images based on text prompts": "Modelo puede generar imágenes basadas en indicadores de texto", "Model can search the web for information": "Modelo puede buscar información en la web", @@ -1314,7 +1340,8 @@ "Models Sharing": "Compartir Modelos", "Mojeek": "Mojeek", "Mojeek Search API Key": "Clave API de Mojeek Search", - "Monthly": "", + "Month": "", + "Monthly": "Mensual", "More": "Más", "More Concise": "Más Conciso", "More options": "Más Opciones", @@ -1332,6 +1359,7 @@ "New Automation": "Nueva Automatización", "New Button": "Nuevo Botón", "New Chat": "Nuevo Chat", + "New Event": "", "New File": "Nuevo Archivo", "New Folder": "Nueva Carpeta", "New Function": "Nueva Función", @@ -1435,7 +1463,7 @@ "Ollama Cloud API Key": "Clave API de Ollama Cloud", "Ollama Version": "Versión de Ollama", "On": "Activado", - "Once": "", + "Once": "Una vez", "OneDrive": "OneDrive", "Only active when \"Paste Large Text as File\" setting is toggled on.": "Solo activo cuando \"Pegar el Texto Largo como Archivo\" está activado", "Only active when the chat input is in focus and an LLM is generating a response.": "Solo activo con el foco en la entrada del chat y se está generando una respuesta", @@ -1501,6 +1529,7 @@ "Password": "Contraseña", "Passwords do not match.": "Las contraseñas no coinciden", "Paste Large Text as File": "Pegar el Texto Largo como Archivo", + "Path copied": "", "Paused": "Pausado", "PDF document (.pdf)": "Documento PDF (.pdf)", "PDF Extract Images (OCR)": "Extraer imágenes del PDF (OCR)", @@ -1520,7 +1549,7 @@ "Persistent": "Persistente", "Personalization": "Personalización", "Pin": "Fijar", - "Pin to Sidebar": "", + "Pin to Sidebar": "Fijar al Panel Lateral", "Pinned": "Fijado", "Pinned Messages": "Mensajes Fijados", "Pinned Models": "Modelos Fijados", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "Esfuerzo del Razonamiento", "Reasoning Tags": "Etiquetas de Razonamiento", "Recently Used": "Usado Recientemente", + "Reconnected": "", "Record": "Grabar", "Record voice": "Grabar voz", "Redirecting you to Open WebUI Community": "Redireccionando a la Comunidad Open-WebUI", @@ -1631,6 +1661,7 @@ "Relevance": "Relevancia", "Relevance Threshold": "Umbral de Relevancia", "Remember Dismissal": "Recordar Descartes (de notificaciones)", + "Reminder": "", "Remove": "Eliminar", "Remove {{MODELID}} from list.": "Eliminar {{MODELID}} de la lista.", "Remove action": "Eliminar acción", @@ -1649,6 +1680,7 @@ "Reply to thread...": "Responder al hilo...", "Replying to {{NAME}}": "Responder a {{NAME}}", "required": "requerido", + "Reranking Batch Size": "", "Reranking Engine": "Motor de Reclasificación", "Reranking Model": "Modelo de Reclasificación", "Reset": "Reiniciar", @@ -1682,7 +1714,7 @@ "Running": "Ejecutando", "Running...": "Ejecutando...", "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "Ejecuta tareas de incrustración concurrentes para acelerar el procesado. Desactivar si se generan problemas (por limitaciones de los motores de incrustracción en uso)", - "Sa_day_of_week": "", + "Sa_day_of_week": "los_sabados", "Save": "Guardar", "Save & Create": "Guardar y Crear", "Save & Update": "Guardar y Actualizar", @@ -1877,7 +1909,12 @@ "Start a new conversation": "Comenzar una conversación nueva", "Start of the channel": "Inicio del canal", "Start Tag": "Etiqueta de Inicio", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Iniciando el núcleo...", + "Starting now": "", "State": "Estado", "Status": "Estado", "Status cleared successfully": "Estado limpiado correctamente", @@ -1899,7 +1936,7 @@ "STT Model": "Modelo STT", "STT Settings": "Ajustes Voz a Texto (STT)", "Stylized PDF Export": "Exportar PDF Estilizado", - "Su_day_of_week": "", + "Su_day_of_week": "los_domingos", "Submit question": "Enviar pregunta", "Submit suggestion": "Enviar sugerencia", "Subtitle": "Subtítulo", @@ -1945,7 +1982,7 @@ "Text Splitter": "Divisor de Texto", "Text-to-Speech": "Texto a Voz", "Text-to-Speech Engine": "Motor Texto a Voz(TTS)", - "Th_day_of_week": "", + "Th_day_of_week": "los jueves", "Thanks for your feedback!": "¡Gracias por tu comentario!", "The Application Account DN you bind with for search": "Cuenta DN de la aplicación vinculada para búsqueda", "The base to search for users": "Base para buscar usuarios", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Esto eliminará {{NAME}} y todo su contenido.", "This will delete all models including custom models": "Esto eliminará todos los modelos, incluidos los modelos personalizados", "This will delete all models including custom models and cannot be undone.": "Esto eliminará todos los modelos, incluidos los modelos personalizados y no se puede deshacer.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Esto reinicializará la base de conocimientos y sincronizará todos los archivos. ¿Desea continuar?", "Thorough explanation": "Explicación exhaustiva", "Thought": "Pensando", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "El título no puede ser una cadena vacía.", "Title Generation": "Generación de Títulos", "Title Generation Prompt": "Indicador para la Generación de Título", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Para acceder a los nombres de modelos disponibles para descargar,", "To access the GGUF models available for downloading,": "Para acceder a los modelos GGUF disponibles para descargar,", @@ -2059,7 +2098,7 @@ "TTS Model": "Modelo TTS", "TTS Settings": "Ajustes Texto a Voz (TTS)", "TTS Voice": "Voz TTS", - "Tu_day_of_week": "", + "Tu_day_of_week": "los martes", "Type": "Tipo", "Type here...": "Teclea aquí...", "Type Hugging Face Resolve (Download) URL": "Escribir la URL de Hugging Face Resolve (Descarga)", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Descargas {{FROM_NOW}}", "Unlock mysteries": "Desbloquear misterios", "Unpin": "Desfijar", + "Unpin from Sidebar": "", "Unravel secrets": "Desentrañar secretos", "Unshare Chat": "Descompartir Chat", "Unsupported file type.": "Tipo de archivo no soportado", @@ -2162,7 +2202,7 @@ "Warning: Enabling this will allow users to run scheduled prompts automatically.": "Aviso: Habilitar esto permitirá a los usuarios ejecutar automáticamente indicadores programados.", "Warning: Enabling this will allow users to upload arbitrary code on the server.": "Aviso: Habilitar esto permitirá a los usuarios subir código arbitrario al servidor.", "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "Aviso: La ejecución Jupyter habilita la ejecución de código arbitrario, planteando graves riesgos de seguridad; Proceder con extrema precaución.", - "We_day_of_week": "", + "We_day_of_week": "los miércoles", "Web": "Web", "Web API": "API Web", "Web Loader Engine": "Motor Cargador Web", @@ -2179,13 +2219,15 @@ "WebUI will make requests to \"{{url}}\"": "WebUI hará solicitudes a \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI hará solicitudes a \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI hará solicitudes a \"{{url}}/chat/completions\"", - "Weekly": "", + "Week": "", + "Weekly": "Semanal", "What are you trying to achieve?": "¿Qué estás tratando de conseguir?", "What are you working on?": "¿En qué estás trabajando?", "What is NOT shared:": "Que NO es compartido:", "What is shared:": "Que es compartido:", "What's New in": "Que hay de Nuevo en", "What's on your mind?": "¿En que estás pensando?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Cuando está habilitado, el modelo responderá a cada mensaje de chat en tiempo real, generando una respuesta tan pronto como se envíe un mensaje. Este modo es útil para aplicaciones de chat en vivo, pero puede afectar al rendimiento en equipos más lentos.", "wherever you are": "dondequiera que estés", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Al paginar la salida. Cada página será separada por una línea horizontal y número de página. Por defecto: Falso", diff --git a/src/lib/i18n/locales/et-EE/translation.json b/src/lib/i18n/locales/et-EE/translation.json index 1d061c333b..a0ce487ea6 100644 --- a/src/lib/i18n/locales/et-EE/translation.json +++ b/src/lib/i18n/locales/et-EE/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} vestlused", "{{webUIName}} Backend Required": "{{webUIName}} taustaserver on vajalik", "*Prompt node ID(s) are required for image generation": "*Sisendi sõlme ID(d) on piltide genereerimiseks vajalikud", + "1 hour before": "", "1 Source": "1 allikas", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1m tagasi", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Koostöökanal, kuhu inimesed liituvad liikmetena", "A discussion channel where access is controlled by groups and permissions": "Arutelukanal, kus juurdepääsu kontrollivad grupid ja õigused", "A new version (v{{LATEST_VERSION}}) is now available.": "Uus versioon (v{{LATEST_VERSION}}) on saadaval.", @@ -47,6 +52,7 @@ "Access Control": "Juurdepääsu kontroll", "Access Grants": "Juurdepääsu andmine", "Access List": "Juurdepääsu nimekiri", + "Access updated": "", "Accessible to all users": "Kättesaadav kõigile kasutajatele", "Account": "Konto", "Account Activation Pending": "Konto aktiveerimine ootel", @@ -72,9 +78,11 @@ "Add content here": "Lisa siia sisu", "Add Custom Parameter": "Lisa kohandatud parameeter", "Add Custom Prompt": "Lisa kohandatud sisend", + "Add description": "", "Add Details": "Lisa üksikasjad", "Add Files": "Lisa faile", "Add Image": "Lisa pilt", + "Add location": "", "Add Member": "Lisa liige", "Add Members": "Lisa liikmeid", "Add Memory": "Lisa mälu", @@ -110,6 +118,7 @@ "AI": "AI", "All": "Kõik", "All chats have been unarchived.": "Kõik vestlused on arhiivist eemaldatud.", + "All day": "", "All models are now hidden": "Kõik mudelid on nüüd peidetud", "All models are now visible": "Kõik mudelid on nüüd nähtavad", "All models deleted successfully": "Kõik mudelid edukalt kustutatud", @@ -198,6 +207,7 @@ "Ask a question": "Esita küsimus", "Assistant": "Assistent", "Async Embedding Processing": "Asünkroonne manustamise töötlemine", + "At time of event": "", "Attach File From Knowledge": "Lisa fail teadmistest", "Attach Files": "", "Attach Knowledge": "Lisa teadmised", @@ -272,6 +282,8 @@ "Bypass Web Loader": "Jäta veebilaadija vahele", "Cache Base Model List": "Puhverda baasmudelite nimekiri", "Calendar": "Kalender", + "Calendar deleted": "", + "Calendars": "", "Call": "Kõne", "Call feature is not supported when using Web STT engine": "Kõnefunktsioon ei ole Web STT mootorit kasutades toetatud", "Camera": "Kaamera", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Ühendu oma OpenAPI-ga ühilduvate väliste tööriistaserveritega.", "Connected ({{type}})": "", "Connection failed": "Ühendus ebaõnnestus", + "Connection lost. Reconnecting...": "", "Connection successful": "Ühendus õnnestus", "Connection Type": "Ühenduse tüüp", "Connections": "Ühendused", @@ -439,6 +452,7 @@ "Copy Last Response": "Kopeeri viimane vastus", "Copy link": "Kopeeri link", "Copy Link": "Kopeeri link", + "Copy Path": "", "Copy Prompt": "Kopeeri sisend", "Copy Share Link": "Kopeeri jagamislink", "Copy to clipboard": "Kopeeri lõikelauale", @@ -519,8 +533,11 @@ "Delete All Chats": "Kustuta kõik vestlused", "Delete all contents inside this folder": "Kustuta kogu selle kausta sisu", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Kustuta vestlus", "Delete chat?": "Kustutada vestlus?", + "Delete Event": "", "Delete File": "Kustuta fail", "Delete folder?": "Kustutada kaust?", "Delete function?": "Kustutada funktsioon?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Viga: mudel ID-ga '{{modelId}}' on juba olemas. Palun valige jätkamiseks erinev ID.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Viga: mudeli ID ei saa olla tühi. Palun sisestage jätkamiseks kehtiv ID.", "Evaluations": "Hindamised", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API võti", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Näide: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Näide: ALL", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "Ühendamine {{URL}} terminali serveriga ebaõnnestus", "Failed to copy link": "Lingi kopeerimine ebaõnnestus", "Failed to create API Key.": "API võtme loomine ebaõnnestus.", + "Failed to delete calendar": "", "Failed to delete note": "Märkme kustutamine ebaõnnestus", "Failed to download image": "Pildi allalaadimine ebaõnnestus", "Failed to extract content from the file: {{error}}": "Failist sisu eraldamine ebaõnnestus: {{error}}", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Piira samaaegseid otsingupäringuid. 0 = piiramatu (vaikimisi). Määrake 1 järjestikuse täitmise jaoks (soovitatav API-de puhul, millel on ranged piirangud, nagu Brave tasuta tase).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Piirab samaaegsete manustamispäringute arvu. Määrake 0 piirangu puudumiseks.", "List": "Nimekiri", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Kuulamine...", "Live": "Reaalajas", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "kohalik", "Local": "Kohalik", "Local Task Model": "Kohalik ülesande mudel", + "Location": "", "Location access not allowed": "Asukoha juurdepääs pole lubatud", "Lost": "Kaotanud", "Low": "Madal", @@ -1273,6 +1297,7 @@ "Model": "Mudel", "Model '{{modelName}}' has been successfully downloaded.": "Mudel '{{modelName}}' on edukalt alla laaditud.", "Model '{{modelTag}}' is already in queue for downloading.": "Mudel '{{modelTag}}' on juba allalaadimise järjekorras.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Mudel {{modelName}} ei ole võimeline visuaalseid sisendeid töötlema", "Model {{name}} is now {{status}}": "Mudel {{name}} on nüüd {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "Mudel {{name}} on nüüd nähtav", "Model accepts file inputs": "Mudel aktsepteerib failisisendeid", "Model accepts image inputs": "Mudel võtab vastu pilte sisendina", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Mudel saab käivitada koodi ja teha arvutusi", "Model can generate images based on text prompts": "Mudel saab teksti põhjal pilte genereerida", "Model can search the web for information": "Mudel saab otsida teavet veebist", @@ -1313,6 +1339,7 @@ "Models Sharing": "Mudelite jagamine", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Search API võti", + "Month": "", "Monthly": "", "More": "Rohkem", "More Concise": "Kokkuvõtlikum", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "Uus nupp", "New Chat": "Uus vestlus", + "New Event": "", "New File": "Uus fail", "New Folder": "Uus kaust", "New Function": "Uus funktsioon", @@ -1500,6 +1528,7 @@ "Password": "Parool", "Passwords do not match.": "Paroolid ei ühti.", "Paste Large Text as File": "Kleebi suur tekst failina", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF dokument (.pdf)", "PDF Extract Images (OCR)": "PDF-ist piltide väljavõtmine (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Arutluspingutus", "Reasoning Tags": "Arutlussildid", "Recently Used": "", + "Reconnected": "", "Record": "Salvesta", "Record voice": "Salvesta hääl", "Redirecting you to Open WebUI Community": "Suunamine Open WebUI kogukonda", @@ -1630,6 +1660,7 @@ "Relevance": "Asjakohasus", "Relevance Threshold": "Asjakohasuse lävi", "Remember Dismissal": "Pea sulgemist meeles", + "Reminder": "", "Remove": "Eemalda", "Remove {{MODELID}} from list.": "Eemalda {{MODELID}} nimekirjast.", "Remove action": "Eemalda toiming", @@ -1648,6 +1679,7 @@ "Reply to thread...": "Vasta lõimele...", "Replying to {{NAME}}": "Vastamine kasutajale {{NAME}}", "required": "nõutav", + "Reranking Batch Size": "", "Reranking Engine": "Ümberjärjestamise mootor", "Reranking Model": "Ümberjärjestamise mudel", "Reset": "Lähtesta", @@ -1875,7 +1907,11 @@ "Start a new conversation": "Alusta uut vestlust", "Start of the channel": "Kanali algus", "Start Tag": "Algussilt", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Kerneli käivitamine...", + "Starting now": "", "State": "", "Status": "Olek", "Status cleared successfully": "Olek edukalt tühjendatud", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "See kustutab {{NAME}} ja kogu selle sisu.", "This will delete all models including custom models": "See kustutab kõik mudelid, sealhulgas kohandatud mudelid", "This will delete all models including custom models and cannot be undone.": "See kustutab kõik mudelid, sealhulgas kohandatud mudelid, ja seda ei saa tagasi võtta.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "See lähtestab teadmiste baasi ja sünkroniseerib kõik failid. Kas soovite jätkata?", "Thorough explanation": "Põhjalik selgitus", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Pealkiri ei saa olla tühi string.", "Title Generation": "Pealkirja genereerimine", "Title Generation Prompt": "Pealkirja genereerimise sisend", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Juurdepääsuks saadaolevatele mudelinimedele allalaadimiseks,", "To access the GGUF models available for downloading,": "Juurdepääsuks allalaadimiseks saadaolevatele GGUF mudelitele,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "Laaditakse maha {{FROM_NOW}}", "Unlock mysteries": "Ava mõistatused", "Unpin": "Eemalda kinnitus", + "Unpin from Sidebar": "", "Unravel secrets": "Ava saladused", "Unshare Chat": "Lõpeta vestluse jagamine", "Unsupported file type.": "Toetamata failitüüp.", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI teeb päringuid aadressile \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI teeb päringuid aadressile \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI teeb päringuid aadressile \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Mida te püüate saavutada?", "What are you working on?": "Millega te tegelete?", @@ -2184,6 +2224,7 @@ "What is shared:": "Mida jagatakse:", "What's New in": "Mis on uut", "What's on your mind?": "Mis teil mõttes on?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Kui see on lubatud, vastab mudel igale vestlussõnumile reaalajas, genereerides vastuse niipea, kui kasutaja sõnumi saadab. See režiim on kasulik reaalajas vestlusrakendustes, kuid võib mõjutada jõudlust aeglasema riistvara puhul.", "wherever you are": "kus iganes te olete", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Kas lehekülgedele jagada. Iga leht eraldatakse horisontaalse joonega ja leheküljenumbriga. Vaikimisi välja lülitatud.", diff --git a/src/lib/i18n/locales/eu-ES/translation.json b/src/lib/i18n/locales/eu-ES/translation.json index af50fb0122..bbb86b2023 100644 --- a/src/lib/i18n/locales/eu-ES/translation.json +++ b/src/lib/i18n/locales/eu-ES/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}-ren Txatak", "{{webUIName}} Backend Required": "{{webUIName}} Backend-a Beharrezkoa", "*Prompt node ID(s) are required for image generation": "Prompt nodoaren IDa(k) beharrezkoak dira irudiak sortzeko", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Bertsio berri bat (v{{LATEST_VERSION}}) eskuragarri dago orain.", @@ -47,6 +52,7 @@ "Access Control": "Sarbide Kontrola", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Erabiltzaile guztientzat eskuragarri", "Account": "Kontua", "Account Activation Pending": "Kontuaren Aktibazioa Zain", @@ -72,9 +78,11 @@ "Add content here": "Gehitu edukia hemen", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Gehitu Fitxategiak", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Gehitu Memoria", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Eredu guztiak ongi ezabatu dira", @@ -198,6 +207,7 @@ "Ask a question": "Egin galdera bat", "Assistant": "Laguntzailea", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "Deia", "Call feature is not supported when using Web STT engine": "Dei funtzioa ez da onartzen Web STT motorra erabiltzean", "Camera": "Kamera", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Konexioak", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Kopiatu Esteka", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Kopiatu arbelera", @@ -519,8 +533,11 @@ "Delete All Chats": "Ezabatu Txat Guztiak", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Ezabatu Txata", "Delete chat?": "Ezabatu txata?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Ezabatu karpeta?", "Delete function?": "Ezabatu funtzioa?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Ebaluazioak", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Adibidea: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Adibidea: GUZTIAK", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Huts egin du API Gakoa sortzean.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Entzuten...", "Live": "", "Llama.cpp": "", @@ -1206,6 +1229,7 @@ "local": "", "Local": "Lokala", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Galduta", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "Modeloa", "Model '{{modelName}}' has been successfully downloaded.": "'{{modelName}}' modeloa ongi deskargatu da.", "Model '{{modelTag}}' is already in queue for downloading.": "'{{modelTag}}' modeloa dagoeneko deskarga ilaran dago.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "{{modelName}} modeloak ez du ikusmen gaitasunik", "Model {{name}} is now {{status}}": "{{name}} modeloa orain {{status}} dago", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "Modeloak irudi sarrerak onartzen ditu", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek bilaketa API gakoa", + "Month": "", "Monthly": "", "More": "Gehiago", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "Txat berria", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "Pasahitza", "Passwords do not match.": "", "Paste Large Text as File": "Itsatsi testu luzea fitxategi gisa", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF dokumentua (.pdf)", "PDF Extract Images (OCR)": "PDF irudiak erauzi (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Grabatu ahotsa", "Redirecting you to Open WebUI Community": "OpenWebUI Komunitatera berbideratzen", @@ -1630,6 +1660,7 @@ "Relevance": "Garrantzia", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Kendu", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Berrantolatze modeloa", "Reset": "Berrezarri", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Kanalaren hasiera", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Honek {{NAME}} eta bere eduki guztiak ezabatuko ditu.", "This will delete all models including custom models": "Honek modelo guztiak ezabatuko ditu, modelo pertsonalizatuak barne", "This will delete all models including custom models and cannot be undone.": "Honek modelo guztiak ezabatuko ditu, modelo pertsonalizatuak barne, eta ezin da desegin.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Honek ezagutza-basea berrezarri eta fitxategi guztiak sinkronizatuko ditu. Jarraitu nahi duzu?", "Thorough explanation": "Azalpen sakona", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Izenburua ezin da kate hutsa izan.", "Title Generation": "", "Title Generation Prompt": "Izenburua sortzeko prompta", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Deskargatzeko eskuragarri dauden modelo izenak atzitzeko,", "To access the GGUF models available for downloading,": "Deskargatzeko eskuragarri dauden GGUF modeloak atzitzeko,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Askatu misterioak", "Unpin": "Kendu aingura", + "Unpin from Sidebar": "", "Unravel secrets": "Askatu sekretuak", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI-k eskaerak egingo ditu \"{{url}}/api/chat\"-era", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI-k eskaerak egingo ditu \"{{url}}/chat/completions\"-era", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Zer lortu nahi duzu?", "What are you working on?": "Zertan ari zara lanean?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "Zer berri honetan:", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Gaituta dagoenean, modeloak txat mezu bakoitzari denbora errealean erantzungo dio, erantzun bat sortuz erabiltzaileak mezua bidaltzen duen bezain laster. Modu hau erabilgarria da zuzeneko txat aplikazioetarako, baina errendimenduan eragina izan dezake hardware motelagoan.", "wherever you are": "zauden tokian zaudela", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/fa-IR/translation.json b/src/lib/i18n/locales/fa-IR/translation.json index cd2f7839a9..39de7bb016 100644 --- a/src/lib/i18n/locales/fa-IR/translation.json +++ b/src/lib/i18n/locales/fa-IR/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} گفتگوهای", "{{webUIName}} Backend Required": "بکند {{webUIName}} نیاز است.", "*Prompt node ID(s) are required for image generation": "*شناسه(های) گره پرامپت برای تولید تصویر مورد نیاز است", + "1 hour before": "", "1 Source": "۱ منبع", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "نسخه جدید (v{{LATEST_VERSION}}) در دسترس است.", @@ -47,6 +52,7 @@ "Access Control": "کنترل دسترسی", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "قابل دسترسی برای همه کاربران", "Account": "حساب کاربری", "Account Activation Pending": "فعال\u200cسازی حساب در حال انتظار", @@ -72,9 +78,11 @@ "Add content here": "محتوا را اینجا اضافه کنید", "Add Custom Parameter": "افزودن پارامتر سفارشی", "Add Custom Prompt": "افزودن پرامپت سفارشی", + "Add description": "", "Add Details": "افزودن جزئیات", "Add Files": "افزودن فایل\u200cها", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "افزودن حافظه", @@ -110,6 +118,7 @@ "AI": "هوش مصنوعی", "All": "همه", "All chats have been unarchived.": "همه چت\u200cها از حالت بایگانی خارج شدند.", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "همه مدل\u200cها با موفقیت حذف شدند", @@ -198,6 +207,7 @@ "Ask a question": "سوالی بپرسید", "Assistant": "دستیار", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "پیوست فایل از دانش", "Attach Files": "", "Attach Knowledge": "پیوست دانش", @@ -272,6 +282,8 @@ "Bypass Web Loader": "دور زدن بارگذاری وب", "Cache Base Model List": "کش لیست مدل پایه", "Calendar": "تقویم", + "Calendar deleted": "", + "Calendars": "", "Call": "تماس", "Call feature is not supported when using Web STT engine": "ویژگی تماس هنگام استفاده از موتور Web STT پشتیبانی نمی\u200cشود", "Camera": "دوربین", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "به سرورهای ابزار خارجی سازگار با OpenAPI خود متصل شوید.", "Connected ({{type}})": "", "Connection failed": "اتصال ناموفق بود", + "Connection lost. Reconnecting...": "", "Connection successful": "اتصال موفقیت\u200cآمیز بود", "Connection Type": "نوع اتصال", "Connections": "ارتباطات", @@ -439,6 +452,7 @@ "Copy Last Response": "کپی آخرین پاسخ", "Copy link": "کپی لینک", "Copy Link": "کپی لینک", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "کپی به کلیپ\u200cبورد", @@ -519,8 +533,11 @@ "Delete All Chats": "حذف همه گفتگوها", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "حذف گپ", "Delete chat?": "گفتگو حذف شود؟", + "Delete Event": "", "Delete File": "", "Delete folder?": "پوشه حذف شود؟", "Delete function?": "تابع حذف شود؟", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "خطا: مدلی با شناسه '{{modelId}}' قبلاً وجود دارد. لطفاً برای ادامه، یک شناسه متفاوت انتخاب کنید.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "خطا: شناسه مدل نمی\u200cتواند خالی باشد. لطفاً برای ادامه، یک شناسه معتبر وارد کنید.", "Evaluations": "ارزیابی\u200cها", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "کلید API اکسا", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "مثال: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "مثال: ALL", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "کپی لینک ناموفق بود", "Failed to create API Key.": "ایجاد کلید API با خطا مواجه شد.", + "Failed to delete calendar": "", "Failed to delete note": "حذف یادداشت ناموفق بود", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "استخراج محتوا از فایل ناموفق بود: {{error}}", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "در حال گوش دادن...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "محلی", "Local": "محلی", "Local Task Model": "مدل وظیفه محلی", + "Location": "", "Location access not allowed": "دسترسی به موقعیت مکانی مجاز نیست", "Lost": "گم شده", "Low": "پایین", @@ -1273,6 +1297,7 @@ "Model": "مدل", "Model '{{modelName}}' has been successfully downloaded.": "مدل '{{modelName}}' با موفقیت دانلود شد.", "Model '{{modelTag}}' is already in queue for downloading.": "مدل '{{modelTag}}' در حال حاضر در صف برای دانلود است.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "مدل {{modelName}} قادر به بینایی نیست", "Model {{name}} is now {{status}}": "مدل {{name}} در حال حاضر {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "مدل {{name}} اکنون قابل مشاهده است", "Model accepts file inputs": "مدل ورودی فایل را می\u200cپذیرد", "Model accepts image inputs": "مدل ورودی تصویر را می\u200cپذیرد", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "مدل می\u200cتواند کد را اجرا کرده و محاسبات را انجام دهد", "Model can generate images based on text prompts": "مدل می\u200cتواند تصاویر را بر اساس پرامپت\u200cهای متنی تولید کند", "Model can search the web for information": "مدل می\u200cتواند وب را برای اطلاعات جستجو کند", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "کلید API جستجوی موجیک", + "Month": "", "Monthly": "", "More": "بیشتر", "More Concise": "خلاصه\u200cتر", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "دکمه جدید", "New Chat": "گپ جدید", + "New Event": "", "New File": "", "New Folder": "پوشه جدید", "New Function": "تابع جدید", @@ -1500,6 +1528,7 @@ "Password": "رمز عبور", "Passwords do not match.": "رمزهای عبور مطابقت ندارند.", "Paste Large Text as File": "چسباندن متن بزرگ به عنوان فایل", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF سند (.pdf)", "PDF Extract Images (OCR)": "استخراج تصاویر از PDF (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "تلاش استدلال", "Reasoning Tags": "تگ\u200cهای استدلال", "Recently Used": "", + "Reconnected": "", "Record": "ضبط", "Record voice": "ضبط صدا", "Redirecting you to Open WebUI Community": "در حال هدایت به OpenWebUI Community", @@ -1630,6 +1660,7 @@ "Relevance": "ارتباط", "Relevance Threshold": "آستانه ارتباط", "Remember Dismissal": "به خاطر سپردن رد کردن", + "Reminder": "", "Remove": "حذف", "Remove {{MODELID}} from list.": "حذف {{MODELID}} از لیست.", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "پاسخ به رشته...", "Replying to {{NAME}}": "در حال پاسخ به {{NAME}}", "required": "مورد نیاز", + "Reranking Batch Size": "", "Reranking Engine": "موتور رتبه\u200cبندی مجدد", "Reranking Model": "مدل ری\u200cشناسی مجدد غیرفعال است", "Reset": "بازنشانی", @@ -1875,7 +1907,11 @@ "Start a new conversation": "شروع یک مکالمه جدید", "Start of the channel": "آغاز کانال", "Start Tag": "تگ شروع", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "این {{NAME}} و تمام محتویات آن را حذف خواهد کرد.", "This will delete all models including custom models": "این همه مدل\u200cها از جمله مدل\u200cهای سفارشی را حذف خواهد کرد", "This will delete all models including custom models and cannot be undone.": "این همه مدل\u200cها از جمله مدل\u200cهای سفارشی را حذف خواهد کرد و قابل بازگشت نیست.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "این پایگاه دانش را بازنشانی کرده و همه فایل\u200cها را همگام\u200cسازی خواهد کرد. آیا می\u200cخواهید ادامه دهید؟", "Thorough explanation": "توضیح کامل", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "عنوان نمی تواند یک رشته خالی باشد.", "Title Generation": "تولید عنوان", "Title Generation Prompt": "پرامپت تولید عنوان", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "برای دسترسی به نام مدل های موجود برای دانلود،", "To access the GGUF models available for downloading,": "برای دسترسی به مدل\u200cهای GGUF موجود برای دانلود،", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "خارج می\u200cشود {{FROM_NOW}}", "Unlock mysteries": "رمزگشایی از اسرار", "Unpin": "برداشتن پین", + "Unpin from Sidebar": "", "Unravel secrets": "کشف رازها", "Unshare Chat": "", "Unsupported file type.": "نوع فایل پشتیبانی نمی\u200cشود.", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI به \"{{url}}\" درخواست خواهد داد", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI به \"{{url}}/api/chat\" درخواست خواهد داد", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI به \"{{url}}/chat/completions\" درخواست خواهد داد", + "Week": "", "Weekly": "", "What are you trying to achieve?": "به دنبال دستیابی به چه هدفی هستید؟", "What are you working on?": "روی چه چیزی کار می\u200cکنید؟", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "چه چیز جدیدی در", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "وقتی فعال باشد، مدل به هر پیام گفتگو در زمان واقعی پاسخ می\u200cدهد و به محض ارسال پیام توسط کاربر، پاسخی تولید می\u200cکند. این حالت برای برنامه\u200cهای گفتگوی زنده مفید است، اما ممکن است در سخت\u200cافزارهای کندتر بر عملکرد تأثیر بگذارد.", "wherever you are": "هر جا که هستید", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "آیا خروجی صفحه\u200cبندی شود یا خیر. هر صفحه با یک خط افقی و شماره صفحه از هم جدا می\u200cشود. پیش\u200cفرض: False.", diff --git a/src/lib/i18n/locales/fi-FI/translation.json b/src/lib/i18n/locales/fi-FI/translation.json index 10d63179d3..16501646eb 100644 --- a/src/lib/i18n/locales/fi-FI/translation.json +++ b/src/lib/i18n/locales/fi-FI/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}:n keskustelut", "{{webUIName}} Backend Required": "{{webUIName}}-backend vaaditaan", "*Prompt node ID(s) are required for image generation": "Kuvan luomiseen vaaditaan kehote-solmun ID(t)", + "1 hour before": "", "1 Source": "1 lähde", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Yhteistyökanava, johon ihmiset liittyvät jäseninä", "A discussion channel where access is controlled by groups and permissions": "Keskustelukanava, johon pääsyä rajoitetaan ryhmillä ja käyttöoikeuksilla", "A new version (v{{LATEST_VERSION}}) is now available.": "Uusi versio (v{{LATEST_VERSION}}) on nyt saatavilla.", @@ -47,6 +52,7 @@ "Access Control": "Käyttöoikeuksien hallinta", "Access Grants": "Käyttöoikeudet", "Access List": "Pääsylista", + "Access updated": "", "Accessible to all users": "Käytettävissä kaikille käyttäjille", "Account": "Tili", "Account Activation Pending": "Tilin aktivointi odottaa", @@ -72,9 +78,11 @@ "Add content here": "Lisää sisältöä tähän", "Add Custom Parameter": "Lisää mukautettu parametri", "Add Custom Prompt": "Lisää mukautettu kehote", + "Add description": "", "Add Details": "Lisää yksityiskohtia", "Add Files": "Lisää tiedostoja", "Add Image": "Lisää kuva", + "Add location": "", "Add Member": "Lisää jäsen", "Add Members": "Lisää jäseniä", "Add Memory": "Lisää muistiin", @@ -110,6 +118,7 @@ "AI": "AI", "All": "Kaikki", "All chats have been unarchived.": "Kaikki keskustelut poistettu arkistosta.", + "All day": "", "All models are now hidden": "Kaikki mallit ovat nyt piilotettu", "All models are now visible": "Kaikki mallit ovat nyt näkyvissä", "All models deleted successfully": "Kaikki mallit poistettu onnistuneesti", @@ -198,6 +207,7 @@ "Ask a question": "Kysy kysymys", "Assistant": "Avustaja", "Async Embedding Processing": "Asynkroninen upotus prosessointi", + "At time of event": "", "Attach File From Knowledge": "Liitä tiedosto tietämyksestä", "Attach Files": "", "Attach Knowledge": "Liitä tietoa", @@ -272,6 +282,8 @@ "Bypass Web Loader": "Ohita verkkolataaja", "Cache Base Model List": "Malli luettelon välimuisti", "Calendar": "Kalenteri", + "Calendar deleted": "", + "Calendars": "", "Call": "Puhelu", "Call feature is not supported when using Web STT engine": "Puhelutoimintoa ei tueta käytettäessä web-puheentunnistusmoottoria", "Camera": "Kamera", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Yhdistä omat ulkopuoliset OpenAPI yhteensopivat työkalu palvelimet.", "Connected ({{type}})": "Yhdistetty ({{type}})", "Connection failed": "Yhteys epäonnistui", + "Connection lost. Reconnecting...": "", "Connection successful": "Yhteys onnistui", "Connection Type": "Yhteystyyppi", "Connections": "Yhteydet", @@ -439,6 +452,7 @@ "Copy Last Response": "Kopioi viimeisin vastaus", "Copy link": "Kopioi linkki", "Copy Link": "Kopioi linkki", + "Copy Path": "", "Copy Prompt": "Kopioi kehote", "Copy Share Link": "Kopioi jakolinkki", "Copy to clipboard": "Kopioi leikepöydälle", @@ -519,8 +533,11 @@ "Delete All Chats": "Poista kaikki keskustelut", "Delete all contents inside this folder": "Poista kaikki sisällöt tästä kansiosta", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Poista keskustelu", "Delete chat?": "Haluatko varmasti poistaa tämän keskustelun?", + "Delete Event": "", "Delete File": "Poista tiedosto", "Delete folder?": "Haluatko varmasti poistaa tämän kansion?", "Delete function?": "Haluatko varmasti poistaa tämän toiminnon?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Virhe: Malli '{{modelId}}' on jo käytössä. Valitse toinen ID jatkaaksesi.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Virhe: Mallin ID ei voi olla tyhjä. Kirjoita ID jatkaaksesi.", "Evaluations": "Arvioinnit", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API -avain", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Esimerkki: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Esimerkki: KAIKKI", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "Yhdistäminen {{URL}} päätepalvelimeen epäonnistui", "Failed to copy link": "Linkin kopiointi epäonnistui", "Failed to create API Key.": "API-avaimen luonti epäonnistui.", + "Failed to delete calendar": "", "Failed to delete note": "Muistiinpanon poistaminen epäonnistui", "Failed to download image": "Kuvan lataaminen epäonnistui", "Failed to extract content from the file: {{error}}": "Tiedoston sisällön pomiminen epäonnistui: {{error}}", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Rajoita samanaikaisia hakukyselyitä. 0 = rajoittamaton (oletus). Aseta arvoon 1 peräkkäistä suoritusta varten (suositellaan API-rajapinnoille, joilla on tiukat nopeusrajoitukset, kuten Brave-ilmaistaso).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Rajoittaa samanaikaisten upotuspyyntöjen määrää. Arvolla 0 ei rajoituksia.", "List": "Lista", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Kuuntelee...", "Live": "Live", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "paikallinen", "Local": "Paikallinen", "Local Task Model": "Paikallinen työmalli", + "Location": "", "Location access not allowed": "Ei pääsyä sijaintitietoihin", "Lost": "Mennyt", "Low": "Matala", @@ -1273,6 +1297,7 @@ "Model": "Malli", "Model '{{modelName}}' has been successfully downloaded.": "Malli '{{modelName}}' ladattiin onnistuneesti.", "Model '{{modelTag}}' is already in queue for downloading.": "Malli '{{modelTag}}' on jo jonossa ladattavaksi.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Malli {{modelName}} ei kykene näkökykyyn", "Model {{name}} is now {{status}}": "Malli {{name}} on nyt {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "Malli {{name}} on nyt näkyvissä", "Model accepts file inputs": "Malli hyväksyy tiedostosyötteet", "Model accepts image inputs": "Malli hyväksyy kuvasyötteitä", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Malli voi suorittaa koodia ja laskelmia", "Model can generate images based on text prompts": "Malli voi luoda kuvia tekstikehotteiden perusteella", "Model can search the web for information": "Malli voi hakea tietoa verkosta", @@ -1313,6 +1339,7 @@ "Models Sharing": "Mallien jako", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API -avain", + "Month": "", "Monthly": "", "More": "Lisää", "More Concise": "Lyhyemmin", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "Uusi painike", "New Chat": "Uusi keskustelu", + "New Event": "", "New File": "Uusi tiedosto", "New Folder": "Uusi kansio", "New Function": "Uusi toiminto", @@ -1500,6 +1528,7 @@ "Password": "Salasana", "Passwords do not match.": "Salasanat eivät täsmää", "Paste Large Text as File": "Liitä suuri teksti tiedostona", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF-asiakirja (.pdf)", "PDF Extract Images (OCR)": "Poimi kuvat PDF:stä (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Päättelyn määrä", "Reasoning Tags": "Päättely tagit", "Recently Used": "", + "Reconnected": "", "Record": "Nauhoita", "Record voice": "Nauhoita ääntä", "Redirecting you to Open WebUI Community": "Ohjataan sinut OpenWebUI-yhteisöön", @@ -1630,6 +1660,7 @@ "Relevance": "Relevanssi", "Relevance Threshold": "Relevanssikynnys", "Remember Dismissal": "Muista sulkeminen", + "Reminder": "", "Remove": "Poista", "Remove {{MODELID}} from list.": "Poista {{MODELID}} listalta", "Remove action": "Poista toiminto", @@ -1648,6 +1679,7 @@ "Reply to thread...": "Vastaa ketjussa...", "Replying to {{NAME}}": "Vastaa {{NAME}}", "required": "vaaditaan", + "Reranking Batch Size": "", "Reranking Engine": "Uudelleenpisteytymismallin moottori", "Reranking Model": "Uudelleenpisteytymismalli", "Reset": "Palauta", @@ -1875,7 +1907,11 @@ "Start a new conversation": "Aloita uusi keskustelu", "Start of the channel": "Kanavan alku", "Start Tag": "Aloitus tagi", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Käynnistetään kerneliä...", + "Starting now": "", "State": "", "Status": "Tila", "Status cleared successfully": "Tila poistettu onnistuneesti", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Tämä poistaa {{NAME}} ja kaikki sen sisällöt.", "This will delete all models including custom models": "Tämä poistaa kaikki mallit mukaan lukien mukautetut mallit", "This will delete all models including custom models and cannot be undone.": "Tämä poistaa kaikki mallit, mukaan lukien mukautetut mallit, eikä sitä voi peruuttaa.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Tämä nollaa tietokannan ja synkronoi kaikki tiedostot. Haluatko jatkaa?", "Thorough explanation": "Perusteellinen selitys", "Thought": "Ajatus", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Otsikko ei voi olla tyhjä merkkijono.", "Title Generation": "Otsikon luonti", "Title Generation Prompt": "Otsikon luontikehote", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Päästäksesi käsiksi ladattavissa oleviin mallinimiin,", "To access the GGUF models available for downloading,": "Päästäksesi käsiksi ladattavissa oleviin GGUF-malleihin,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "Purkuja {{FROM_NOW}}", "Unlock mysteries": "Selvitä arvoituksia", "Unpin": "Irrota kiinnitys", + "Unpin from Sidebar": "", "Unravel secrets": "Avaa salaisuuksia", "Unshare Chat": "Lopeta keskustelun jakaminen", "Unsupported file type.": "Ei tuettu tiedostotyyppi", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI lähettää pyyntöjä osoitteeseen \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI lähettää pyyntöjä osoitteeseen \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI lähettää pyyntöjä osoitteeseen \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Mitä yrität saavuttaa?", "What are you working on?": "Mitä olet työskentelemässä?", @@ -2184,6 +2224,7 @@ "What is shared:": "Mitä jaetaan:", "What's New in": "Mitä uutta", "What's on your mind?": "Mitä ajattelet?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Kun käytössä, malli vastaa jokaiseen chatviestiin reaaliajassa, tuottaen vastauksen heti kun käyttäjä lähettää viestin. Tämä tila on hyödyllinen reaaliaikaisissa chat-sovelluksissa, mutta voi vaikuttaa suorituskykyyn hitaammilla laitteistoilla.", "wherever you are": "missä tahansa oletkin", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Sivutetaanko tuloste. Jokainen sivu erotetaan toisistaan vaakasuoralla viivalla ja sivunumerolla. Oletusarvo ei käytössä.", diff --git a/src/lib/i18n/locales/fr-CA/translation.json b/src/lib/i18n/locales/fr-CA/translation.json index b0f58be103..d59ea0abf3 100644 --- a/src/lib/i18n/locales/fr-CA/translation.json +++ b/src/lib/i18n/locales/fr-CA/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Conversations de {{user}}", "{{webUIName}} Backend Required": "Backend {{webUIName}} requis", "*Prompt node ID(s) are required for image generation": "*Les ID de noeud du prompt sont nécessaires pour la génération d'images", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Une nouvelle version (v{{LATEST_VERSION}}) est disponible.", @@ -48,6 +53,7 @@ "Access Control": "Contrôle d'accès", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Accessible à tous les utilisateurs", "Account": "Compte", "Account Activation Pending": "Activation du compte en attente", @@ -73,9 +79,11 @@ "Add content here": "Ajoutez du contenu ici", "Add Custom Parameter": "Ajoutez votre réglage personnalisé", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Ajouter des fichiers", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Ajouter un souvenir", @@ -111,6 +119,7 @@ "AI": "", "All": "Tout", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Tous les modèles ont été supprimés avec succès", @@ -199,6 +208,7 @@ "Ask a question": "Posez votre question", "Assistant": "Assistant", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -273,6 +283,8 @@ "Bypass Web Loader": "Ignorer le chargeur Web", "Cache Base Model List": "Mettre en cache la liste des modèles de base", "Calendar": "Calendrier", + "Calendar deleted": "", + "Calendars": "", "Call": "Appeler", "Call feature is not supported when using Web STT engine": "La fonction d'appel n'est pas prise en charge lors de l'utilisation du moteur Web STT", "Camera": "Appareil photo", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Connectez-vous à vos serveurs d'outils externes.", "Connected ({{type}})": "", "Connection failed": "Échec de la connexion", + "Connection lost. Reconnecting...": "", "Connection successful": "Connexion réussie", "Connection Type": "Type de connexion", "Connections": "Connexions", @@ -440,6 +453,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Copier le lien", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Copier dans le presse-papiers", @@ -520,8 +534,11 @@ "Delete All Chats": "Supprimer toutes les conversations", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Supprimer la Conversation", "Delete chat?": "Supprimer la conversation ?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Supprimer le dossier ?", "Delete function?": "Supprimer la fonction ?", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Évaluations", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Clé d'Exa API", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemple: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exemple: TOUS", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Échec de la copie du lien", "Failed to create API Key.": "Échec de la création de la clé API.", + "Failed to delete calendar": "", "Failed to delete note": "Échec de la délétion de la note", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Écoute en cours...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1230,7 @@ "local": "", "Local": "Local", "Local Task Model": "Model de tâche local", + "Location": "", "Location access not allowed": "Accès à la localisation non autorisé", "Lost": "Perdu", "Low": "", @@ -1274,6 +1298,7 @@ "Model": "Modèle", "Model '{{modelName}}' has been successfully downloaded.": "Le modèle '{{modelName}}' a été téléchargé avec succès.", "Model '{{modelTag}}' is already in queue for downloading.": "Le modèle '{{modelTag}}' est déjà dans la file d'attente pour le téléchargement.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Le modèle {{modelName}} n'a pas de capacités visuelles", "Model {{name}} is now {{status}}": "Le modèle {{name}} est désormais {{status}}.", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "Le modèle {{name}} est maintenant visible", "Model accepts file inputs": "Le modèle accepte les fichiers en entrée", "Model accepts image inputs": "Le modèle accepte les images en entrée", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Le modèle peut executer du code et faire des calculs", "Model can generate images based on text prompts": "Le modèle peut générer des images à partir des prompts textuels", "Model can search the web for information": "Le modèle peut faire des recherches sur internet pour trouver des informations", @@ -1314,6 +1340,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Clé API Mojeek", + "Month": "", "Monthly": "", "More": "Plus", "More Concise": "", @@ -1332,6 +1359,7 @@ "New Automation": "", "New Button": "", "New Chat": "Nouvelle conversation", + "New Event": "", "New File": "", "New Folder": "Nouveau dossier", "New Function": "Nouvelle fonction", @@ -1501,6 +1529,7 @@ "Password": "Mot de passe", "Passwords do not match.": "", "Paste Large Text as File": "Coller un texte volumineux comme fichier", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Document au format PDF (.pdf)", "PDF Extract Images (OCR)": "Extraction d'images PDF (OCR)", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "Effort de raisonnement", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Enregistrement", "Record voice": "Enregistrer la voix", "Redirecting you to Open WebUI Community": "Redirection vers la communauté OpenWebUI", @@ -1631,6 +1661,7 @@ "Relevance": "Pertinence", "Relevance Threshold": "Seuil de pertinence", "Remember Dismissal": "Se souvenir du rejet", + "Reminder": "", "Remove": "Retirer", "Remove {{MODELID}} from list.": "Retirer {{MODELID}} de la liste.", "Remove action": "", @@ -1649,6 +1680,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "Moteur de ré-ranking", "Reranking Model": "Modèle de ré-ranking", "Reset": "Réinitialiser", @@ -1877,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "Début du canal", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Cela supprimera {{NAME}} et tout son contenu.", "This will delete all models including custom models": "Cela supprimera tous les modèles, y compris les modèles personnalisés", "This will delete all models including custom models and cannot be undone.": "Cela supprimera tous les modèles, y compris les modèles personnalisés, et ne peut pas être annulé.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Cela réinitialisera la base de connaissances et synchronisera tous les fichiers. Souhaitez-vous continuer ?", "Thorough explanation": "Explication approfondie", "Thought": "", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "Le titre ne peut pas être une chaîne de caractères vide.", "Title Generation": "Génération du Titre", "Title Generation Prompt": "Prompt de génération de titre", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Pour accéder aux noms des modèles disponibles,", "To access the GGUF models available for downloading,": "Pour accéder aux modèles GGUF disponibles,", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Décharge {{FROM_NOW}}", "Unlock mysteries": "Déverrouiller les mystères", "Unpin": "Désépingler", + "Unpin from Sidebar": "", "Unravel secrets": "Dévoiler les secrets", "Unshare Chat": "", "Unsupported file type.": "", @@ -2179,6 +2219,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI effectuera des requêtes vers \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI fera des requêtes à \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI fera des requêtes à \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Que cherchez-vous à accomplir ?", "What are you working on?": "Sur quoi travaillez-vous ?", @@ -2186,6 +2227,7 @@ "What is shared:": "", "What's New in": "Quoi de neuf dans", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Lorsqu'il est activé, le modèle répondra à chaque message de la conversation en temps réel, générant une réponse dès que l'utilisateur envoie un message. Ce mode est utile pour les applications de conversation en direct, mais peut affecter les performances sur un matériel plus lent.", "wherever you are": "où que vous soyez", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Indique si la sortie doit être paginée. Chaque page sera séparée par une règle horizontale et un numéro de page. La valeur par défaut est False.", diff --git a/src/lib/i18n/locales/fr-FR/translation.json b/src/lib/i18n/locales/fr-FR/translation.json index 60c85440d3..4572e362c8 100644 --- a/src/lib/i18n/locales/fr-FR/translation.json +++ b/src/lib/i18n/locales/fr-FR/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Conversations de {{user}}", "{{webUIName}} Backend Required": "Backend {{webUIName}} requis", "*Prompt node ID(s) are required for image generation": "*Les ID de noeud du prompt sont nécessaires pour la génération d'image", + "1 hour before": "", "1 Source": "1 Source", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1min", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Un canal collaboratif où les membres rejoignent librement", "A discussion channel where access is controlled by groups and permissions": "Un canal de discussion où l'accès est contrôlé par les groupes et les permissions", "A new version (v{{LATEST_VERSION}}) is now available.": "Une nouvelle version (v{{LATEST_VERSION}}) est disponible.", @@ -48,6 +53,7 @@ "Access Control": "Contrôle d'accès", "Access Grants": "Droits d'accès", "Access List": "Liste des accès", + "Access updated": "", "Accessible to all users": "Accessible à tous les utilisateurs", "Account": "Compte", "Account Activation Pending": "Activation du compte en attente", @@ -73,9 +79,11 @@ "Add content here": "Ajoutez du contenu ici", "Add Custom Parameter": "Ajoutez votre réglage personnalisé", "Add Custom Prompt": "Ajouter un prompt personnalisé", + "Add description": "", "Add Details": "Ajouter des détails", "Add Files": "Ajouter des fichiers", "Add Image": "Ajouter une image", + "Add location": "", "Add Member": "Ajouter un membre", "Add Members": "Ajouter des membres", "Add Memory": "Ajouter un souvenir", @@ -111,6 +119,7 @@ "AI": "IA", "All": "Tout", "All chats have been unarchived.": "Toutes les conversations ont été désarchivées.", + "All day": "", "All models are now hidden": "Tous les modèles sont maintenant masqués", "All models are now visible": "Tous les modèles sont maintenant visibles", "All models deleted successfully": "Tous les modèles supprimés avec succès", @@ -199,6 +208,7 @@ "Ask a question": "Posez votre question", "Assistant": "Assistant", "Async Embedding Processing": "Traitement asynchrone des embeddings", + "At time of event": "", "Attach File From Knowledge": "Joindre un fichier depuis les connaissances", "Attach Files": "", "Attach Knowledge": "Joindre une connaissance", @@ -273,6 +283,8 @@ "Bypass Web Loader": "Ignorer le chargeur Web", "Cache Base Model List": "Mettre en cache la liste des modèles de base", "Calendar": "Calendrier", + "Calendar deleted": "", + "Calendars": "", "Call": "Appeler", "Call feature is not supported when using Web STT engine": "La fonction d'appel n'est pas prise en charge lors de l'utilisation du moteur Web STT", "Camera": "Appareil photo", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Connectez-vous à vos serveurs d'outils externes.", "Connected ({{type}})": "", "Connection failed": "Échec de la connexion", + "Connection lost. Reconnecting...": "", "Connection successful": "Connexion réussie", "Connection Type": "Type de connexion", "Connections": "Connexions", @@ -440,6 +453,7 @@ "Copy Last Response": "Copier la dernière réponse", "Copy link": "Copier le lien", "Copy Link": "Copier le lien", + "Copy Path": "", "Copy Prompt": "Copier le prompt", "Copy Share Link": "Copier le lien de partage", "Copy to clipboard": "Copier dans le presse-papiers", @@ -520,8 +534,11 @@ "Delete All Chats": "Supprimer toutes les conversations", "Delete all contents inside this folder": "Supprimer tout le contenu de ce dossier", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Supprimer la Conversation", "Delete chat?": "Supprimer la conversation ?", + "Delete Event": "", "Delete File": "Supprimer le fichier", "Delete folder?": "Supprimer le dossier ?", "Delete function?": "Supprimer la fonction ?", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Erreur : Un modèle avec l'ID '{{modelId}}' existe déjà. Veuillez sélectionner un ID différent pour continuer.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Erreur : l'ID du modèle ne peut pas être vide. Veuillez saisir un ID valide pour continuer.", "Evaluations": "Évaluations", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Clé API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemple: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exemple: TOUS", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "Échec de la connexion au serveur de terminal {{URL}}", "Failed to copy link": "Échec de la copie du lien", "Failed to create API Key.": "Échec de la création de la clé API.", + "Failed to delete calendar": "", "Failed to delete note": "Échec de la délétion de la note", "Failed to download image": "Échec du téléchargement de l'image", "Failed to extract content from the file: {{error}}": "Échec de l'extraction du contenu du fichier : {{error}}", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limite les requêtes de recherche simultanées. 0 = illimité (par défaut). Définir à 1 pour une exécution séquentielle (recommandé pour les API avec des limites de débit strictes comme Brave gratuit).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limite le nombre de requêtes d'embedding simultanées. Définir à 0 pour illimité.", "List": "Liste", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Écoute en cours...", "Live": "Actif", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1230,7 @@ "local": "local", "Local": "Local", "Local Task Model": "Model de tâche local", + "Location": "", "Location access not allowed": "Accès à la localisation non autorisé", "Lost": "Perdu", "Low": "Faible", @@ -1274,6 +1298,7 @@ "Model": "Modèle", "Model '{{modelName}}' has been successfully downloaded.": "Le modèle '{{modelName}}' a été téléchargé avec succès.", "Model '{{modelTag}}' is already in queue for downloading.": "Le modèle '{{modelTag}}' est déjà dans la file d'attente pour le téléchargement.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Le modèle {{modelName}} n'a pas de fonctionnalité de vision", "Model {{name}} is now {{status}}": "Le modèle {{name}} est désormais {{status}}.", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "Le modèle {{name}} est maintenant visible", "Model accepts file inputs": "Le modèle accepte des fichiers en entrée", "Model accepts image inputs": "Le modèle accepte des images en entrée", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Le modèle peut exécuter du code et faire des calculs", "Model can generate images based on text prompts": "Le modèle peut générer des images à partir de prompts", "Model can search the web for information": "Le modèle peut faire des recherches sur internet pour trouver des informations", @@ -1314,6 +1340,7 @@ "Models Sharing": "Partage des modèles", "Mojeek": "Mojeek", "Mojeek Search API Key": "Clé API Mojeek", + "Month": "", "Monthly": "", "More": "Plus", "More Concise": "Plus concis", @@ -1332,6 +1359,7 @@ "New Automation": "", "New Button": "Nouveau bouton", "New Chat": "Nouvelle conversation", + "New Event": "", "New File": "Nouveau fichier", "New Folder": "Nouveau dossier", "New Function": "Nouvelle fonction", @@ -1501,6 +1529,7 @@ "Password": "Mot de passe", "Passwords do not match.": "Les mots de passe ne correspondent pas.", "Paste Large Text as File": "Coller un texte volumineux comme fichier", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Document au format PDF (.pdf)", "PDF Extract Images (OCR)": "Extraction d'images PDF (OCR)", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "Effort de raisonnement", "Reasoning Tags": "Balises de raisonnement", "Recently Used": "", + "Reconnected": "", "Record": "Enregistrement", "Record voice": "Enregistrer la voix", "Redirecting you to Open WebUI Community": "Redirection vers la communauté OpenWebUI", @@ -1631,6 +1661,7 @@ "Relevance": "Pertinence", "Relevance Threshold": "Seuil de pertinence", "Remember Dismissal": "Se souvenir du rejet", + "Reminder": "", "Remove": "Retirer", "Remove {{MODELID}} from list.": "Retirer {{MODELID}} de la liste.", "Remove action": "Retirer l'action", @@ -1649,6 +1680,7 @@ "Reply to thread...": "Répondre au fil de discussion...", "Replying to {{NAME}}": "En réponse à {{NAME}}", "required": "requis", + "Reranking Batch Size": "", "Reranking Engine": "Moteur de ré-ranking", "Reranking Model": "Modèle de ré-ranking", "Reset": "Réinitialiser", @@ -1877,7 +1909,12 @@ "Start a new conversation": "Démarrer une nouvelle conversation", "Start of the channel": "Début du canal", "Start Tag": "Balise de départ", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Démarrage du noyau...", + "Starting now": "", "State": "", "Status": "Statut", "Status cleared successfully": "Statut effacé avec succès", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Cela supprimera {{NAME}} et tout son contenu.", "This will delete all models including custom models": "Cela supprimera tous les modèles, y compris les modèles personnalisés", "This will delete all models including custom models and cannot be undone.": "Cela supprimera tous les modèles, y compris les modèles personnalisés, et ne peut pas être annulé.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Cela réinitialisera la base de connaissances et synchronisera tous les fichiers. Souhaitez-vous continuer ?", "Thorough explanation": "Explication approfondie", "Thought": "", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "Le titre ne peut pas être une chaîne de caractères vide.", "Title Generation": "Génération du Titre", "Title Generation Prompt": "Prompt de génération de titre", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Pour accéder aux noms des modèles disponibles,", "To access the GGUF models available for downloading,": "Pour accéder aux modèles GGUF disponibles,", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Décharge {{FROM_NOW}}", "Unlock mysteries": "Déverrouiller les mystères", "Unpin": "Désépingler", + "Unpin from Sidebar": "", "Unravel secrets": "Dévoiler les secrets", "Unshare Chat": "Annuler le partage de la conversation", "Unsupported file type.": "Type de fichier non pris en charge.", @@ -2179,6 +2219,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI effectuera des requêtes vers \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI fera des requêtes à \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI fera des requêtes à \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Que cherchez-vous à accomplir ?", "What are you working on?": "Sur quoi travaillez-vous ?", @@ -2186,6 +2227,7 @@ "What is shared:": "Ce qui est partagé :", "What's New in": "Quoi de neuf dans", "What's on your mind?": "Quoi de neuf ?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Lorsqu'il est activé, le modèle répondra à chaque message de la conversation en temps réel, générant une réponse dès que l'utilisateur envoie un message. Ce mode est utile pour les applications de conversation en direct, mais peut affecter les performances sur un matériel plus lent.", "wherever you are": "où que vous soyez", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Indique si la sortie doit être paginée. Chaque page sera séparée par une règle horizontale et un numéro de page. La valeur par défaut est False.", diff --git a/src/lib/i18n/locales/gl-ES/translation.json b/src/lib/i18n/locales/gl-ES/translation.json index 19fad395d1..df434bfa1a 100644 --- a/src/lib/i18n/locales/gl-ES/translation.json +++ b/src/lib/i18n/locales/gl-ES/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "Chats do {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Servidor Requerido", "*Prompt node ID(s) are required for image generation": "Os ID do nodo son requeridos para a xeneración de imáxes", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Unha nova versión (v{{LATEST_VERSION}}) está disponible.", @@ -47,6 +52,7 @@ "Access Control": "Control de Acceso", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Accesible para todos os usuarios", "Account": "Conta", "Account Activation Pending": "Activación da conta pendente", @@ -72,9 +78,11 @@ "Add content here": "Agrege contido aquí", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Agregar Arquivos", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Agregar Memoria", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Todos os modelos han sido borrados", @@ -198,6 +207,7 @@ "Ask a question": "Fai unha pregunta", "Assistant": "Asistente", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "Chamada", "Call feature is not supported when using Web STT engine": "A funcionalidade da chamada non pode usarse xunto co motor da STT Web", "Camera": "Cámara", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Conexions", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Copiar enlace", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Copiado o portapapeis", @@ -519,8 +533,11 @@ "Delete All Chats": "Eliminar todos os chats", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Borrar Chat", "Delete chat?": "Borrar o chat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "¿Eliminar carpeta?", "Delete function?": "Borrar afunción?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Evaluacions", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "chave API de Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemplo: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exemplo: TODOS", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Non pudo xerarse a chave API.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Escoitando...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "", "Local": "Local", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Perdido", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "Modelo", "Model '{{modelName}}' has been successfully downloaded.": "0 modelo '{{modelName}}' se ha descargado correctamente.", "Model '{{modelTag}}' is already in queue for downloading.": "0 modelo '{{modelTag}}' ya está en cola para descargar.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "O modelo {{modelName}} no es capaz de ver", "Model {{name}} is now {{status}}": "O modelo {{name}} ahora es {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "O modelo acepta entradas de imaxenes", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "chave API de Mojeek Search", + "Month": "", "Monthly": "", "More": "mais", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "Novo Chat", + "New Event": "", "New File": "", "New Folder": "Nova carpeta", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "Contrasinal ", "Passwords do not match.": "", "Paste Large Text as File": "Pegar texto grande como arquivo", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Documento PDF (.pdf)", "PDF Extract Images (OCR)": "Extraer imaxes de PDF (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Esfuerzo de razonamiento", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Grabar voz", "Redirecting you to Open WebUI Community": "Redireccionándote a a comunidad OpenWebUI", @@ -1630,6 +1660,7 @@ "Relevance": "Relevancia", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Eliminar", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Modelo de reranking", "Reset": "Reiniciar", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Inicio da canle", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Esto eliminará {{NAME}} y todo su contido.", "This will delete all models including custom models": "Esto eliminará todos os modelos, incluidos os modelos personalizados", "This will delete all models including custom models and cannot be undone.": "Esto eliminará todos os modelos, incluidos os modelos personalizados y no se puede deshacer.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Esto reseteará la base de coñecementos y sincronizará todos os arquivos. ¿Desea continuar?", "Thorough explanation": "Explicación exhaustiva", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "O título non pode ser unha cadena vacía.", "Title Generation": "Xeneración de titulos", "Title Generation Prompt": "Prompt de xeneración de título", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Para acceder os nomes de modelos dispoñibles para descargar,", "To access the GGUF models available for downloading,": "Para acceder os modelos GGUF dispoñibles para descargar,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Desbloquear misterios", "Unpin": "Desanclar", + "Unpin from Sidebar": "", "Unravel secrets": "Desentrañar secretos", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI hará solicitudes a \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI hará solicitudes a \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "¿Qué estás tratando de lograr?", "What are you working on?": "¿En qué estás trabajando?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "Novedades en", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Cando está habilitado, o modelo responderá a cada mensaxe de chat en tempo real, generando unha resposta tan pronto como o usuario envíe un mensaxe. Este modo es útil para aplicacions de chat en vivo, pero puede afectar o rendimiento en hardware mais lento.", "wherever you are": "Donde queira que estés", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/he-IL/translation.json b/src/lib/i18n/locales/he-IL/translation.json index a273c87c71..f36e6d332e 100644 --- a/src/lib/i18n/locales/he-IL/translation.json +++ b/src/lib/i18n/locales/he-IL/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "צ'אטים של {{user}}", "{{webUIName}} Backend Required": "נדרש Backend של {{webUIName}}", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -48,6 +53,7 @@ "Access Control": "בקרת גישה", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "חשבון", "Account Activation Pending": "", @@ -73,9 +79,11 @@ "Add content here": "הוסף תוכן כאן", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "הוסף קבצים", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "הוסף זיכרון", @@ -111,6 +119,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "כל המודלים נמחקו בהצלחה", @@ -199,6 +208,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -273,6 +283,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "לוח שנה", + "Calendar deleted": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "מצלמה", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "החיבור נכשל", + "Connection lost. Reconnecting...": "", "Connection successful": "החיבור הצליח", "Connection Type": "סוג חיבור", "Connections": "חיבורים", @@ -440,6 +453,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "העתק קישור", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -520,8 +534,11 @@ "Delete All Chats": "מחק את כל הצ'אטים", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "מחק צ'אט", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "יצירת מפתח API נכשלה.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1207,6 +1230,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1274,6 +1298,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "המודל '{{modelName}}' הורד בהצלחה.", "Model '{{modelTag}}' is already in queue for downloading.": "המודל '{{modelTag}}' כבר בתור להורדה.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "דגם {{modelName}} אינו בעל יכולת ראייה", "Model {{name}} is now {{status}}": "דגם {{name}} הוא כעת {{status}}", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1314,6 +1340,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "עוד", "More Concise": "", @@ -1332,6 +1359,7 @@ "New Automation": "", "New Button": "", "New Chat": "צ'אט חדש", + "New Event": "", "New File": "", "New Folder": "תיקייה חדשה", "New Function": "פונקציה חדשה", @@ -1501,6 +1529,7 @@ "Password": "סיסמה", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "מסמך PDF (.pdf)", "PDF Extract Images (OCR)": "חילוץ תמונות מ-PDF (OCR)", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "הקלט קול", "Redirecting you to Open WebUI Community": "מפנה אותך לקהילת OpenWebUI", @@ -1631,6 +1661,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "הסר", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1649,6 +1680,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "מודל דירוג מחדש", "Reset": "", @@ -1877,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "תחילת הערוץ", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_two": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "תיאור מפורט", "Thought": "", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "שם לא יכול להיות מחרוזת ריקה.", "Title Generation": "", "Title Generation Prompt": "פרומפט ליצירת כותרת", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "כדי לגשת לשמות הדגמים הזמינים להורדה,", "To access the GGUF models available for downloading,": "כדי לגשת לדגמי GGUF הזמינים להורדה,", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2179,6 +2219,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2186,6 +2227,7 @@ "What is shared:": "", "What's New in": "מה חדש ב", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/hi-IN/translation.json b/src/lib/i18n/locales/hi-IN/translation.json index b2d1252c76..eeeff64210 100644 --- a/src/lib/i18n/locales/hi-IN/translation.json +++ b/src/lib/i18n/locales/hi-IN/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} की चैट", "{{webUIName}} Backend Required": "{{webUIName}} बैकएंड आवश्यक", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -47,6 +52,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "खाता", "Account Activation Pending": "", @@ -72,9 +78,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "फाइलें जोड़ें", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "मेमोरी जोड़ें", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -198,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "सम्बन्ध", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "लिंक को कॉपी करें", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -460,8 +474,8 @@ "Create Image": "", "Create Knowledge": "", "Create Model": "", - "Create new key": "नया क्रिप्टोग्राफिक क्षेत्र बनाएं", - "Create new secret key": "नया क्रिप्टोग्राफिक क्षेत्र बनाएं", + "Create new key": "नई कुंजी बनाएं", + "Create new secret key": "नई गुप्त कुंजी बनाएं", "Create note": "", "Create Note": "", "Create scheduled prompts that run automatically on a recurring basis.": "", @@ -519,8 +533,11 @@ "Delete All Chats": "सभी चैट हटाएं", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "चैट हटाएं", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -815,7 +832,7 @@ "Entra ID": "", "Environment Variables": "", "Ephemeral": "", - "Error": "चूक", + "Error": "त्रुटि", "ERROR": "", "Error accessing directory": "", "Error accessing Google Drive: {{error}}": "", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -845,7 +866,7 @@ "Explore the cosmos": "", "Explored": "", "Exploring": "", - "Export": "निर्यातित माल", + "Export": "निर्यात करें", "Export All Archived Chats": "", "Export All Chats (All Users)": "सभी चैट निर्यात करें (सभी उपयोगकर्ताओं की)", "Export as CSV": "", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "एपीआई कुंजी बनाने में विफल.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1093,7 +1115,7 @@ "Includes SharePoint": "SharePoint शामिल है", "Increase UI Scale": "", "Influences how quickly the algorithm responds to feedback from the generated text. A lower learning rate will result in slower adjustments, while a higher learning rate will make the algorithm more responsive.": "", - "Info": "सूचना-विषयक", + "Info": "जानकारी", "Initials": "", "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", @@ -1126,7 +1148,7 @@ "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "मदद के लिए हमारे डिस्कोर्ड में शामिल हों।", - "JSON": "ज्ञान प्रकार", + "JSON": "JSON", "JSON Preview": "JSON पूर्वावलोकन", "JSON Spec": "", "July": "जुलाई", @@ -1192,10 +1214,11 @@ "lexical": "", "License": "", "Lift List": "", - "Light": "सुन", + "Light": "हल्का", "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1206,6 +1229,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "मॉडल '{{modelName}}' सफलतापूर्वक डाउनलोड हो गया है।", "Model '{{modelTag}}' is already in queue for downloading.": "मॉडल '{{modelTag}}' पहले से ही डाउनलोड करने के लिए कतार में है।", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "मॉडल {{modelName}} दृष्टि सक्षम नहीं है", "Model {{name}} is now {{status}}": "मॉडल {{name}} अब {{status}} है", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "और..", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "नई चैट", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1427,7 +1455,7 @@ "October": "अक्टूबर", "Off": "बंद", "Okay, Let's Go!": "ठीक है, चलिए चलते हैं!", - "OLED Dark": "OLEDescuro", + "OLED Dark": "OLED डार्क", "Ollama": "Ollama", "Ollama API": "ओलामा एपीआई", "Ollama API settings updated": "", @@ -1500,6 +1528,7 @@ "Password": "पासवर्ड", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF दस्तावेज़ (.pdf)", "PDF Extract Images (OCR)": "PDF छवियाँ निकालें (OCR)", @@ -1533,7 +1562,7 @@ "Pipelines Valves": "पाइपलाइन वाल्व", "Plain text (.md)": "", "Plain text (.txt)": "सादा पाठ (.txt)", - "Playground": "कार्यक्षेत्र", + "Playground": "प्रयोगशाला", "Playwright Timeout (ms)": "", "Playwright WebSocket URL": "", "Please carefully review the following warnings:": "", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "आवाज रिकॉर्ड करना", "Redirecting you to Open WebUI Community": "आपको OpenWebUI समुदाय पर पुनर्निर्देशित किया जा रहा है", @@ -1630,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "हटा दें", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "रीरैकिंग मोड", "Reset": "", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "चैनल की शुरुआत", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "विस्तृत व्याख्या", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "शीर्षक नहीं खाली पाठ हो सकता है.", "Title Generation": "", "Title Generation Prompt": "शीर्षक जनरेशन प्रॉम्प्ट", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "डाउनलोड करने के लिए उपलब्ध मॉडल नामों तक पहुंचने के लिए,", "To access the GGUF models available for downloading,": "डाउनलोडिंग के लिए उपलब्ध GGUF मॉडल तक पहुँचने के लिए,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "इसमें नया क्या है", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", @@ -2231,7 +2272,7 @@ "You have no shared conversations.": "", "You have shared this chat": "आपने इस चैट को शेयर किया है", "You.com API Key": "", - "You're a helpful assistant.": "आप एक सहायक सहायक हैं", + "You're a helpful assistant.": "आप एक मददगार सहायक हैं।", "You're now logged in.": "अब आप लॉग इन हो गए हैं", "Your Account": "", "Your account status is currently pending activation.": "", diff --git a/src/lib/i18n/locales/hr-HR/translation.json b/src/lib/i18n/locales/hr-HR/translation.json index 5bf1a7e65c..c0525013e9 100644 --- a/src/lib/i18n/locales/hr-HR/translation.json +++ b/src/lib/i18n/locales/hr-HR/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Razgovori korisnika {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Backend je potreban", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -48,6 +53,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "Račun", "Account Activation Pending": "", @@ -73,9 +79,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Dodaj datoteke", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Dodaj memoriju", @@ -111,6 +119,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -199,6 +208,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -273,6 +283,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "Poziv", "Call feature is not supported when using Web STT engine": "Značajka poziva nije podržana kada se koristi Web STT mehanizam", "Camera": "Kamera", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Povezivanja", @@ -440,6 +453,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Kopiraj vezu", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -520,8 +534,11 @@ "Delete All Chats": "Izbriši sve razgovore", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Izbriši razgovor", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Neuspješno stvaranje API ključa.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Slušam...", "Live": "", "Llama.cpp": "", @@ -1207,6 +1230,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1274,6 +1298,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "Model '{{modelName}}' je uspješno preuzet.", "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' je već u redu za preuzimanje.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Model {{modelName}} ne čita vizualne impute", "Model {{name}} is now {{status}}": "Model {{name}} sada je {{status}}", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1314,6 +1340,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Više", "More Concise": "", @@ -1332,6 +1359,7 @@ "New Automation": "", "New Button": "", "New Chat": "Novi razgovor", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1501,6 +1529,7 @@ "Password": "Lozinka", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF dokument (.pdf)", "PDF Extract Images (OCR)": "PDF izdvajanje slika (OCR)", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Snimanje glasa", "Redirecting you to Open WebUI Community": "Preusmjeravanje na OpenWebUI zajednicu", @@ -1631,6 +1661,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Ukloni", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1649,6 +1680,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Model za ponovno rangiranje", "Reset": "", @@ -1877,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "Početak kanala", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "Detaljno objašnjenje", "Thought": "", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "Naslov ne može biti prazni niz.", "Title Generation": "", "Title Generation Prompt": "Prompt za generiranje naslova", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Za pristup dostupnim nazivima modela za preuzimanje,", "To access the GGUF models available for downloading,": "Za pristup GGUF modelima dostupnim za preuzimanje,", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2179,6 +2219,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2186,6 +2227,7 @@ "What is shared:": "", "What's New in": "Što je novo u", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/hu-HU/translation.json b/src/lib/i18n/locales/hu-HU/translation.json index 362977a7f0..22f4ea62cf 100644 --- a/src/lib/i18n/locales/hu-HU/translation.json +++ b/src/lib/i18n/locales/hu-HU/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} beszélgetései", "{{webUIName}} Backend Required": "{{webUIName}} Backend szükséges", "*Prompt node ID(s) are required for image generation": "*Prompt node ID(k) szükségesek a képgeneráláshoz", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Új verzió (v{{LATEST_VERSION}}) érhető el.", @@ -47,6 +52,7 @@ "Access Control": "Hozzáférés-vezérlés", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Minden felhasználó számára elérhető", "Account": "Fiók", "Account Activation Pending": "Fiók aktiválása folyamatban", @@ -72,9 +78,11 @@ "Add content here": "Tartalom hozzáadása ide", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Fájlok hozzáadása", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Memória hozzáadása", @@ -110,6 +118,7 @@ "AI": "", "All": "Mind", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Minden modell sikeresen törölve", @@ -198,6 +207,7 @@ "Ask a question": "Kérdezz valamit", "Assistant": "Asszisztens", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Naptár", + "Calendar deleted": "", + "Calendars": "", "Call": "Hívás", "Call feature is not supported when using Web STT engine": "A hívás funkció nem támogatott Web STT motor használatakor", "Camera": "Kamera", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Csatlakozz saját OpenAPI kompatibilis külső eszköszervereidhez.", "Connected ({{type}})": "", "Connection failed": "Kapcsolat sikertelen", + "Connection lost. Reconnecting...": "", "Connection successful": "Kapcsolat sikeres", "Connection Type": "", "Connections": "Kapcsolatok", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Link másolása", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Másolás a vágólapra", @@ -519,8 +533,11 @@ "Delete All Chats": "Minden beszélgetés törlése", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Beszélgetés törlése", "Delete chat?": "Törli a beszélgetést?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Törli a mappát?", "Delete function?": "Törli a funkciót?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Értékelések", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API kulcs", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Példa: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Példa: MIND", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Nem sikerült létrehozni az API kulcsot.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Hallgatás...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "", "Local": "Helyi", "Local Task Model": "", + "Location": "", "Location access not allowed": "Helyhozzáférés nem engedélyezett", "Lost": "Elveszett", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "Modell", "Model '{{modelName}}' has been successfully downloaded.": "A '{{modelName}}' modell sikeresen letöltve.", "Model '{{modelTag}}' is already in queue for downloading.": "A '{{modelTag}}' modell már a letöltési sorban van.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "A {{modelName}} modell nem képes képfeldolgozásra", "Model {{name}} is now {{status}}": "A {{name}} modell most {{status}} állapotban van", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "A {{name}} modell most látható", "Model accepts file inputs": "", "Model accepts image inputs": "A modell elfogad képbemenetet", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API kulcs", + "Month": "", "Monthly": "", "More": "Több", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "Új beszélgetés", + "New Event": "", "New File": "", "New Folder": "Új mappa", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "Jelszó", "Passwords do not match.": "", "Paste Large Text as File": "Nagy szöveg beillesztése fájlként", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF dokumentum (.pdf)", "PDF Extract Images (OCR)": "PDF képek kinyerése (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Érvelési erőfeszítés", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Hang rögzítése", "Redirecting you to Open WebUI Community": "Átirányítás az OpenWebUI közösséghez", @@ -1630,6 +1660,7 @@ "Relevance": "Relevancia", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Eltávolítás", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Újrarangsoroló modell", "Reset": "Visszaállítás", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "A csatorna eleje", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Ez törölni fogja a {{NAME}}-t és minden tartalmát.", "This will delete all models including custom models": "Ez törölni fogja az összes modellt, beleértve az egyéni modelleket is", "This will delete all models including custom models and cannot be undone.": "Ez törölni fogja az összes modellt, beleértve az egyéni modelleket is, és nem vonható vissza.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Ez visszaállítja a tudásbázist és szinkronizálja az összes fájlt. Szeretné folytatni?", "Thorough explanation": "Alapos magyarázat", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "A cím nem lehet üres karakterlánc.", "Title Generation": "Cím generálás", "Title Generation Prompt": "Cím generálási prompt", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "A letölthető modellek nevének eléréséhez,", "To access the GGUF models available for downloading,": "A letölthető GGUF modellek eléréséhez,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Titkok feloldása", "Unpin": "Rögzítés feloldása", + "Unpin from Sidebar": "", "Unravel secrets": "Titkok megfejtése", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "A WebUI kéréseket küld a \"{{url}}\" címre", "WebUI will make requests to \"{{url}}/api/chat\"": "A WebUI kéréseket küld a \"{{url}}/api/chat\" címre", "WebUI will make requests to \"{{url}}/chat/completions\"": "A WebUI kéréseket küld a \"{{url}}/chat/completions\" címre", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Mit próbálsz elérni?", "What are you working on?": "Min dolgozol?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "Mi újság a", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Ha engedélyezve van, a modell valós időben válaszol minden csevegőüzenetre, amint a felhasználó elküldi az üzenetet. Ez a mód hasznos élő csevegőalkalmazásokhoz, de lassabb hardveren befolyásolhatja a teljesítményt.", "wherever you are": "bárhol is vagy", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/id-ID/translation.json b/src/lib/i18n/locales/id-ID/translation.json index 80317e4361..c537fb24bb 100644 --- a/src/lib/i18n/locales/id-ID/translation.json +++ b/src/lib/i18n/locales/id-ID/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "Obrolan {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Diperlukan Backend", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -46,6 +51,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "Akun", "Account Activation Pending": "Aktivasi Akun Tertunda", @@ -71,9 +77,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Menambahkan File", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Menambahkan Memori", @@ -109,6 +117,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -197,6 +206,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -271,6 +281,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "Panggilan", "Call feature is not supported when using Web STT engine": "Fitur panggilan tidak didukung saat menggunakan mesin Web STT", "Camera": "Kamera", @@ -407,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Koneksi", @@ -438,6 +451,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Salin Tautan", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -518,8 +532,11 @@ "Delete All Chats": "Menghapus Semua Obrolan", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Menghapus Obrolan", "Delete chat?": "Menghapus obrolan?", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "Fungsi hapus?", @@ -826,6 +843,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -874,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Gagal membuat API Key.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1195,6 +1217,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Mendengarkan", "Live": "", "Llama.cpp": "", @@ -1205,6 +1228,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1272,6 +1296,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "Model '{{modelName}}' telah berhasil diunduh.", "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' sudah berada dalam antrean untuk diunduh.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Model {{modelName}} tidak dapat dilihat", "Model {{name}} is now {{status}}": "Model {{name}} sekarang menjadi {{status}}", @@ -1279,6 +1304,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1312,6 +1338,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Lainnya", "More Concise": "", @@ -1330,6 +1357,7 @@ "New Automation": "", "New Button": "", "New Chat": "Obrolan Baru", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1499,6 +1527,7 @@ "Password": "Kata sandi", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Dokumen PDF (.pdf)", "PDF Extract Images (OCR)": "Ekstrak Gambar PDF (OCR)", @@ -1606,6 +1635,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Rekam suara", "Redirecting you to Open WebUI Community": "Mengarahkan Anda ke Komunitas OpenWebUI", @@ -1629,6 +1659,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Hapus", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1647,6 +1678,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Model Pemeringkatan Ulang", "Reset": "Atur Ulang", @@ -1873,7 +1905,10 @@ "Start a new conversation": "", "Start of the channel": "Awal saluran", "Start Tag": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1986,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "Penjelasan menyeluruh", "Thought": "", @@ -2005,6 +2041,7 @@ "Title cannot be an empty string.": "Judul tidak boleh berupa string kosong.", "Title Generation": "", "Title Generation Prompt": "Perintah Pembuatan Judul", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Untuk mengakses nama model yang tersedia untuk diunduh,", "To access the GGUF models available for downloading,": "Untuk mengakses model GGUF yang tersedia untuk diunduh,", @@ -2071,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2175,6 +2213,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2182,6 +2221,7 @@ "What is shared:": "", "What's New in": "Apa yang Baru di", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/ie-GA/translation.json b/src/lib/i18n/locales/ie-GA/translation.json index 2fa16b9a30..e5550ac069 100644 --- a/src/lib/i18n/locales/ie-GA/translation.json +++ b/src/lib/i18n/locales/ie-GA/translation.json @@ -17,8 +17,8 @@ "{{COUNT}} members": "{{COUNT}} ball", "{{COUNT}} Replies": "{{COUNT}} Freagra", "{{COUNT}} Rows": "{{COUNT}} Sraitheanna", - "{{count}} selected_one": "", - "{{count}} selected_other": "", + "{{count}} selected_one": "{{count}} mir roghnaithe", + "{{count}} selected_other": "{{count}} míreanna roghnaithe", "{{COUNT}} Sources": "{{COUNT}} Foinsí", "{{COUNT}} words": "{{COUNT}} focail", "{{COUNT}}d_time_ago": "l", @@ -32,9 +32,14 @@ "{{NAMES}} reacted with {{REACTION}}": "D’fhreagair {{NAMES}} le {{REACTION}}", "{{user}}'s Chats": "Comhráite {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Ceoldeireadh Riachtanach", - "*Prompt node ID(s) are required for image generation": "* Tá ID nód leid ag teastáil chun íomhá a ghiniúint", + "*Prompt node ID(s) are required for image generation": "* Tá ID(anna) nód treorach ag teastáil chun íomhá a ghiniúint", + "1 hour before": "", "1 Source": "1 Foinse", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1 nóiméad ó shin", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Cainéal comhoibrithe ina mbíonn daoine ag glacadh páirte mar bhaill", "A discussion channel where access is controlled by groups and permissions": "Cainéal plé ina bhfuil rochtain rialaithe ag grúpaí agus ceadanna", "A new version (v{{LATEST_VERSION}}) is now available.": "Tá leagan nua (v {{LATEST_VERSION}}) ar fáil anois.", @@ -42,11 +47,12 @@ "A task model is used when performing tasks such as generating titles for chats and web search queries": "Úsáidtear samhail tascanna agus tascanna á ndéanamh amhail teidil a ghiniúint le haghaidh comhráite agus fiosrúcháin chuardaigh ghréasáin", "a user": "úsáideoir", "About": "Maidir", - "Accept Autocomplete Generation\nJump to Prompt Variable": "Glac le Giniúint Uathchríochnaithe\nLéim go dtí an Athróg Pras", + "Accept Autocomplete Generation\nJump to Prompt Variable": "Glac le Giniúint Uathchríochnaithe\nLéim go dtí Athróg na Treorach", "Access": "Rochtain", "Access Control": "Rialaithe Rochtana", "Access Grants": "Deontais Rochtana", "Access List": "Liosta Rochtana", + "Access updated": "", "Accessible to all users": "Inrochtana do gach úsáideoir", "Account": "Cuntas", "Account Activation Pending": "Gníomhachtaithe Cuntas", @@ -71,10 +77,12 @@ "Add Content": "Cuir Ábhar leis", "Add content here": "Cuir ábhar anseo", "Add Custom Parameter": "Cuir Paraiméadar Saincheaptha leis", - "Add Custom Prompt": "Cuir Leid Saincheaptha leis", + "Add Custom Prompt": "Cuir Treoir Shaincheaptha leis", + "Add description": "", "Add Details": "Cuir Sonraí leis", "Add Files": "Cuir Comhaid", "Add Image": "Cuir Íomhá leis", + "Add location": "", "Add Member": "Cuir Ball leis", "Add Members": "Cuir Baill leis", "Add Memory": "Cuir Cuimhne", @@ -110,6 +118,7 @@ "AI": "IS", "All": "Gach", "All chats have been unarchived.": "Tá na comhráite uile díchartlannaithe.", + "All day": "", "All models are now hidden": "Tá na samhlacha uile i bhfolach anois", "All models are now visible": "Tá na samhlacha uile le feiceáil anois", "All models deleted successfully": "Scriosadh na samhlacha go léir go rathúil", @@ -122,14 +131,14 @@ "Allow Chat Export": "Ceadaigh Easpórtáil Comhrá", "Allow Chat Params": "Ceadaigh Paraiméadair Comhrá", "Allow Chat Share": "Ceadaigh Comhroinnt Comhrá", - "Allow Chat System Prompt": "Ceadaigh Pras Córais Comhrá", + "Allow Chat System Prompt": "Ceadaigh Treoir Chórais Comhrá", "Allow Chat Valves": "Ceadaigh Comhlaí Comhrá", "Allow Continue Response": "Ceadaigh Leanúint ar aghaidh leis an bhFreagra", "Allow Delete Messages": "Ceadaigh Teachtaireachtaí a Scriosadh", "Allow File Upload": "Ceadaigh Uaslódáil Comhad", "Allow Multiple Models in Chat": "Ceadaigh Il-Samhlacha i gComhrá", - "Allow non-local voices": "Lig guthanna neamh-áitiúla", - "Allow public write access": "", + "Allow non-local voices": "Ceadaigh guthanna neamh-áitiúla", + "Allow public write access": "Ceadaigh rochtain scríbhneoireachta phoiblí", "Allow Rate Response": "Ceadaigh Freagairt Ráta", "Allow Regenerate Response": "Ceadaigh Freagra Athghiniúint", "Allow Sharing With Users": "Ceadaigh Comhroinnt le hÚsáideoirí", @@ -182,14 +191,14 @@ "Are you sure you want to archive all chats? This action cannot be undone.": "An bhfuil tú cinnte gur mian leat na comhráite go léir a chartlannú? Ní féidir an gníomh seo a chealú.", "Are you sure you want to clear all memories? This action cannot be undone.": "An bhfuil tú cinnte gur mhaith leat na cuimhní go léir a ghlanadh? Ní féidir an gníomh seo a chealú.", "Are you sure you want to delete \"{{NAME}}\"?": "An bhfuil tú cinnte gur mian leat \"{{NAME}}\" a scriosadh?", - "Are you sure you want to delete **{{modelName}}**?": "", + "Are you sure you want to delete **{{modelName}}**?": "An bhfuil tú cinnte gur mian leat **{{modelName}}** a scriosadh?", "Are you sure you want to delete all chats? This action cannot be undone.": "An bhfuil tú cinnte gur mian leat na comhráite go léir a scriosadh? Ní féidir an gníomh seo a chealú.", "Are you sure you want to delete this channel?": "An bhfuil tú cinnte gur mhaith leat an cainéal seo a scriosadh?", - "Are you sure you want to delete this connection? This action cannot be undone.": "", - "Are you sure you want to delete this memory? This action cannot be undone.": "", + "Are you sure you want to delete this connection? This action cannot be undone.": "An bhfuil tú cinnte gur mian leat an nasc seo a scriosadh? Ní féidir an gníomh seo a chealú.", + "Are you sure you want to delete this memory? This action cannot be undone.": "An bhfuil tú cinnte gur mian leat an chuimhne seo a scriosadh? Ní féidir an gníomh seo a chealú.", "Are you sure you want to delete this message?": "An bhfuil tú cinnte gur mhaith leat an teachtaireacht seo a scriosadh?", "Are you sure you want to delete this version? Child versions will be relinked to this version's parent.": "An bhfuil tú cinnte gur mian leat an leagan seo a scriosadh? Déanfar leaganacha linbh a athnascadh le tuismitheoir an leagain seo.", - "Are you sure you want to delete this?": "", + "Are you sure you want to delete this?": "An bhfuil tú cinnte gur mian leat é seo a scriosadh?", "Are you sure you want to unarchive all archived chats?": "An bhfuil tú cinnte gur mhaith leat gach comhrá cartlainne a dhíchartlannú?", "Arena Models": "Samhlacha Réimse", "Artifacts": "Déantáin", @@ -198,8 +207,9 @@ "Ask a question": "Cuir ceist", "Assistant": "Cúntóir", "Async Embedding Processing": "Próiseáil Leabaithe Asyncrónach", + "At time of event": "", "Attach File From Knowledge": "Ceangail Comhad ó Eolas", - "Attach Files": "", + "Attach Files": "Ceangail Comhaid", "Attach Knowledge": "Ceangail Eolas", "Attach Notes": "Ceangail Nótaí", "Attach Webpage": "Ceangail Leathanach Gréasáin", @@ -222,13 +232,13 @@ "AUTOMATIC1111 Base URL": "UATHOIBRÍOCH1111 Bun URL", "AUTOMATIC1111 Base URL is required.": "Tá URL bonn UATHOIBRÍOCH1111 ag teastáil.", "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "Uirlisí córais a instealladh go huathoibríoch i mód glaonna feidhme dúchais (m.sh., stampaí ama, cuimhne, stair comhrá, nótaí, srl.)", - "Automation": "", - "Automation created": "", - "Automation Name": "", - "Automation title": "", - "Automation triggered": "", - "Automation updated": "", - "Automations": "", + "Automation": "Uathoibriú", + "Automation created": "Uathoibriú cruthaithe", + "Automation Name": "Ainm uathoibrithe", + "Automation title": "Teideal uathoibrithe", + "Automation triggered": "Uathoibriú spreagtha", + "Automation updated": "Uathoibriú nuashonraithe", + "Automations": "Uathoibrithe", "Available list": "Liosta atá ar fáil", "Available models": "Samhlacha atá ar fáil", "Available Tools": "Uirlisí ar Fáil", @@ -259,19 +269,21 @@ "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Treisiú nó pionós a ghearradh ar chomharthaí sonracha as freagraí srianta. Déanfar luachanna laofachta a chlampáil idir -100 agus 100 (san áireamh). (Réamhshocrú: ceann ar bith)", "Brave": "Brave", "Brave Search API Key": "Eochair API Cuardaigh Brave", - "Break down complex requests into trackable steps": "", + "Break down complex requests into trackable steps": "Bris síos iarratais chasta i gcéimeanna inrianaithe", "Browse and query knowledge bases": "Brabhsáil agus fiosraigh bunachair eolais", "Builtin Tools": "Uirlisí Tógtha", "Bullet List": "Liosta Urchair", "Button ID": "Aitheantas an Chnaipe", "Button Label": "Lipéad Cnaipe", - "Button Prompt": "Leid Cnaipe", + "Button Prompt": "Treoir Cnaipe", "by {{name}}": "le {{name}}", "By {{name}}": "Le {{name}}", "Bypass Embedding and Retrieval": "Seachbhóthar Leabú agus Aisghabháil", "Bypass Web Loader": "Seachbhóthar Luchtaire Gréasáin", "Cache Base Model List": "Liosta Samhail Bunáite Taisce", "Calendar": "Féilire", + "Calendar deleted": "", + "Calendars": "", "Call": "Glaoigh", "Call feature is not supported when using Web STT engine": "Ní thacaítear le gné glaonna agus inneall Web STT á úsáid", "Camera": "Ceamara", @@ -298,7 +310,7 @@ "Character limit for autocomplete generation input": "Teorainn charachtair le haghaidh ionchur giniúna uathchríochnaithe", "Chart new frontiers": "Cairt teorainneacha nua", "Chat": "Comhrá", - "Chat archived.": "", + "Chat archived.": "Comhrá cartlannaithe.", "Chat Background Image": "Íomhá Cúlra Comhrá", "Chat Bubble UI": "Comhrá Bubble UI", "Chat Completions": "Críochnuithe Comhrá", @@ -341,10 +353,10 @@ "Click here to upload a workflow.json file.": "Cliceáil anseo chun comhad workflow.json a uaslódáil.", "click here.": "cliceáil anseo.", "Click on the user role button to change a user's role.": "Cliceáil ar an gcnaipe ról úsáideora chun ról úsáideora a athrú.", - "Click to connect": "", + "Click to connect": "Cliceáil chun ceangal", "Click to copy ID": "Cliceáil chun an t-aitheantas a chóipeáil", - "Client ID": "", - "Client Secret": "", + "Client ID": "Aitheantas Cliant", + "Client Secret": "Rún an Chliaint", "Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Diúltaíodh cead scríofa an ghearrthaisce. Seiceáil socruithe do bhrabhsálaí chun an rochtain riachtanach a dheonú.", "Clone": "Clón", "Clone Chat": "Comhrá Clón", @@ -370,7 +382,7 @@ "Code formatted successfully": "Cód formáidithe go rathúil", "Code Interpreter": "Ateangaire Cód", "Code Interpreter Engine": "Inneall Ateangaire Cóid", - "Code Interpreter Prompt Template": "Teimpléad Pras Ateangaire Cód", + "Code Interpreter Prompt Template": "Teimpléad Treorach Ateangaire Cód", "Collaboration channel where people join as members": "Cainéal comhoibrithe ina mbíonn daoine páirteach mar bhaill", "Collapse": "Laghdaigh", "Collection": "Bailiúchán", @@ -393,11 +405,11 @@ "Concurrent Requests": "Iarrataí Comhthéime", "Config": "Cumraíocht", "Config imported successfully": "Cumraíocht allmhairithe go rathúil", - "Configuration": "", + "Configuration": "Cumraíocht", "Configure": "Cumraigh", "Confirm": "Deimhnigh", "Confirm Password": "Deimhnigh Pasfhocal", - "Confirm Prompt from Embed": "", + "Confirm Prompt from Embed": "Deimhnigh Treoir ón Leabú", "Confirm your action": "Deimhnigh do ghníomh", "Confirm your new password": "Deimhnigh do phasfhocal nua", "Confirm Your Password": "Deimhnigh Do Phasfhocal", @@ -406,8 +418,9 @@ "Connect to Open Terminal instances. All users will have access to file browsing and terminal tools through these servers.": "Ceangail le cásanna Open Terminal. Beidh rochtain ag gach úsáideoir ar bhrabhsáil comhad agus uirlisí críochfoirt trí na freastalaithe seo.", "Connect to your own OpenAI compatible API endpoints.": "Ceangail le do chríochphointí API atá comhoiriúnach le OpenAI.", "Connect to your own OpenAPI compatible external tool servers.": "Ceangail le do fhreastalaithe uirlisí seachtracha atá comhoiriúnach le OpenAPI.", - "Connected ({{type}})": "", + "Connected ({{type}})": "Ceangailte ({{type}})", "Connection failed": "Theip ar an gceangal", + "Connection lost. Reconnecting...": "", "Connection successful": "Ceangal rathúil", "Connection Type": "Cineál Ceangail", "Connections": "Naisc", @@ -439,7 +452,8 @@ "Copy Last Response": "Cóipeáil an Fhreagra Deiridh", "Copy link": "Cóipeáil nasc", "Copy Link": "Cóipeáil Nasc", - "Copy Prompt": "CCóipeáil an Treoir", + "Copy Path": "", + "Copy Prompt": "Cóipeáil an Treoir", "Copy Share Link": "Cóipeáil Nasc Comhroinnte", "Copy to clipboard": "Cóipeáil chuig an ngearrthaisce", "Copy Token": "Cóipeáil Comhartha", @@ -447,14 +461,14 @@ "Copying to clipboard was successful!": "D'éirigh le cóipeáil chuig an ngearrthaisce!", "CORS must be properly configured by the provider to allow requests from Open WebUI.": "Ní mór don soláthraí CORS a chumrú i gceart chun iarratais ó Open WebUI a cheadú.", "Could not read file.": "Níorbh fhéidir an comhad a léamh.", - "CPU": "", + "CPU": "LAP", "Create": "Cruthaigh", "Create a knowledge base": "Cruthaigh bonn eolais", "Create a model": "Cruthaigh samhail", "Create a new note": "Cruthaigh nóta nua", "Create Account": "Cruthaigh Cuntas", "Create Admin Account": "Cruthaigh Cuntas Riaracháin", - "Create and manage scheduled automations": "", + "Create and manage scheduled automations": "Cruthaigh agus bainistigh uathoibrithe sceidealaithe", "Create Channel": "Cruthaigh Cainéal", "Create Folder": "Cruthaigh Fillteán", "Create Image": "Cruthaigh Íomhá", @@ -464,7 +478,7 @@ "Create new secret key": "Cruthaigh eochair rúnda nua", "Create note": "Cruthaigh nóta", "Create Note": "Cruthaigh Nóta", - "Create scheduled prompts that run automatically on a recurring basis.": "", + "Create scheduled prompts that run automatically on a recurring basis.": "Cruthaigh leideanna sceidealaithe a ritheann go huathoibríoch ar bhonn athfhillteach.", "Create your first note by clicking on the plus button below.": "Cruthaigh do chéad nóta trí chliceáil ar an gcnaipe móide thíos.", "Created at": "Cruthaithe ag", "Created At": "Cruthaithe Ag", @@ -480,14 +494,14 @@ "Custom Gender": "Inscne Saincheaptha", "Custom Parameter Name": "Ainm Paraiméadair Saincheaptha", "Custom Parameter Value": "Luach Paraiméadair Saincheaptha", - "Daily": "", + "Daily": "Laethúil", "Daily Messages": "Teachtaireachtaí Laethúla", "Danger Zone": "Crios Contúirte", "Dark": "Dorcha", "Data Controls": "Rialuithe Sonraí", "Database": "Bunachar Sonraí", "Datalab Marker API": "API Marcóra Datalab", - "Day": "", + "Day": "Lá", "DD/MM/YYYY": "DD/MM/YYYY", "DDGS Backend": "Cúltaca DDGS", "December": "Nollaig", @@ -506,30 +520,33 @@ "Default model updated": "Nuashonraithe samhail réamhshocraithe", "Default permissions": "Ceadanna réamhshocraithe", "Default permissions updated successfully": "D'éirigh le ceadanna réamhshocraithe a nuashonrú", - "Default Prompt Suggestions": "Moltaí Leid Réamhshocraithe", + "Default Prompt Suggestions": "Moltaí Treoracha Réamhshocraithe", "Default to 389 or 636 if TLS is enabled": "Réamhshocrú go 389 nó 636 má tá TLS cumasaithe", "Default to ALL": "Réamhshocrú do GACH", "Default to segmented retrieval for focused and relevant content extraction, this is recommended for most cases.": "Réamhshocrú maidir le haisghabháil deighilte d'eastóscadh ábhar dírithe agus ábhartha, moltar é seo i bhformhór na gcásanna.", "Default User Role": "Ról Úsáideora Réamhshocraithe", "Defaults": "Réamhshocruithe", "Delete": "Scrios", - "Delete {{name}}": "", + "Delete {{name}}": "Scrios {{name}}", "Delete a model": "Scrios samhail", "Delete All": "Scrios Gach Rud", "Delete All Chats": "Scrios Gach Comhrá", "Delete all contents inside this folder": "Scrios an t-ábhar go léir atá sa fhillteán seo", - "Delete automation?": "", + "Delete automation?": "Scrios an t-uathoibriú?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Scrios Comhrá", "Delete chat?": "Scrios comhrá?", + "Delete Event": "", "Delete File": "Scrios Comhad", "Delete folder?": "Scrios fillteán?", "Delete function?": "Scrios feidhm?", - "Delete Memory?": "", + "Delete Memory?": "Scrios Cuimhne?", "Delete Message": "Scrios Teachtaireacht", "Delete message?": "Scrios teachtaireacht?", "Delete Model": "Scrios an tSamhail", "Delete note?": "Scrios an nóta?", - "Delete prompt?": "Scrios leid?", + "Delete prompt?": "Scrios an treoir?", "Delete skill?": "Scrios an scil?", "delete this link": "scrios an nasc seo", "Delete tool?": "Uirlis a scriosadh?", @@ -538,7 +555,7 @@ "Deleted": "Scriosta", "Deleted {{deleteModelTag}}": "Scriosta {{deleteModelTag}}", "Deleted {{name}}": "Scriosta {{name}}", - "Deleted {{ok}} of {{total}} items": "", + "Deleted {{ok}} of {{total}} items": "Scriosadh {{ok}} de {{total}} míreanna", "Deleted User": "Úsáideoir Scriosta", "Deployment names are required for Azure OpenAI": "Tá ainmneacha imscartha ag teastáil le haghaidh Azure OpenAI", "Desc": "Cur Síos", @@ -547,7 +564,7 @@ "Describe what changed...": "Déan cur síos ar a bhfuil athraithe...", "Describe your knowledge base and objectives": "Déan cur síos ar do bhunachar eolais agus do chuspóirí", "Description": "Cur síos", - "Deselect": "", + "Deselect": "Díroghnaigh", "Detect Artifacts Automatically": "Déan Déantáin a bhrath go huathoibríoch", "Dictate": "Deachtaigh", "Didn't fully follow instructions": "Níor lean sé treoracha go hiomlán", @@ -564,14 +581,14 @@ "Disabled": "Díchumasaithe", "Discover a function": "Faigh amach feidhm", "Discover a model": "Faigh amach samhail", - "Discover a prompt": "Faigh amach leid", + "Discover a prompt": "Faigh amach treoir", "Discover a tool": "Faigh amach uirlis", "Discover how to use Open WebUI and seek support from the community.": "Faigh amach conas Open WebUI a úsáid agus lorg tacaíocht ón bpobal.", "Discover wonders": "Faigh amach iontais", "Discover, download, and explore custom functions": "Faigh amach, íoslódáil agus iniúchadh feidhmeanna saincheaptha", - "Discover, download, and explore custom prompts": "Leideanna saincheaptha a fháil amach, a íoslódáil agus a iniúchadh", - "Discover, download, and explore custom tools": "Uirlisí saincheaptha a fháil amach, íoslódáil agus iniúchadh", - "Discover, download, and explore model presets": "Réamhshocruithe samhail a fháil amach, a íoslódáil agus a iniúchadh", + "Discover, download, and explore custom prompts": "Faigh amach, íoslódáil agus iniúch treoracha saincheaptha", + "Discover, download, and explore custom tools": "Faigh amach, íoslódáil agus taiscéal uirlisí saincheaptha", + "Discover, download, and explore model presets": "Faigh amach, íoslódáil agus réamhshocruithe samhail a iniúchadh", "Discussion channel where access is based on groups and permissions": "Cainéal plé ina bhfuil rochtain bunaithe ar ghrúpaí agus ceadanna", "Display": "Taispeáin", "Display chat title in tab": "Taispeáin teideal an chomhrá sa chluaisín", @@ -610,7 +627,7 @@ "Downloading stats...": "Ag íoslódáil staitisticí...", "Draw": "Tarraing", "Drop any files here to upload": "Scaoil aon chomhaid anseo le huaslódáil", - "Drop files here": "", + "Drop files here": "Scaoil comhaid anseo", "Drop files here to upload": "Scaoil comhaid anseo le huaslódáil", "DuckDuckGo": "DuckDuckGo", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "m.sh. '30s', '10m'. Is iad aonaid ama bailí ná 's', 'm', 'h'.", @@ -663,8 +680,8 @@ "Embedding Concurrent Requests": "Iarratais Chomhuaineacha a Leabú", "Embedding Model": "Samhail Leabháilte", "Embedding Model Engine": "Inneall Samhail Leabaithe", - "Emojis": "", - "Empty message": "", + "Emojis": "Emoji", + "Empty message": "Teachtaireacht folamh", "Enable All": "Cumasaigh Gach Rud", "Enable API Keys": "Cumasaigh Eochracha API", "Enable autocomplete generation for chat messages": "Cumasaigh giniúint uathchríochnaithe le haghaidh teachtaireachtaí comhrá", @@ -755,7 +772,7 @@ "Enter Perplexity Search API URL": "Cuir isteach URL API Cuardaigh na Measctha", "Enter Playwright Timeout": "Iontráil Teorainn Ama na nDrámadóir", "Enter Playwright WebSocket URL": "Cuir isteach URL WebSocket Seinmeora", - "Enter prompt here.": "", + "Enter prompt here.": "Cuir isteach an treoir anseo.", "Enter proxy URL (e.g. https://user:password@host:port)": "Cuir isteach URL seachfhreastalaí (m.sh. https://user:password@host:port)", "Enter reasoning effort": "Cuir isteach iarracht réasúnaíochta", "Enter Score": "Iontráil Scór", @@ -776,11 +793,11 @@ "Enter Sougou Search API sID": "Cuir isteach sID Sougou Search API", "Enter Sougou Search API SK": "Cuir isteach Sougou Search API SK", "Enter stop sequence": "Cuir isteach seicheamh stad", - "Enter system prompt": "Cuir isteach an chóras leid", - "Enter system prompt here": "Cuir leid córais isteach anseo", + "Enter system prompt": "Cuir isteach treoir chórais", + "Enter system prompt here": "Cuir isteach treoir chórais anseo", "Enter Tavily API Key": "Cuir isteach eochair API Tavily", "Enter Tavily Extract Depth": "Cuir isteach Doimhneacht Sliocht Tavily", - "Enter the prompt instructions for this automation...": "", + "Enter the prompt instructions for this automation...": "Cuir isteach treoracha na treorach don uathoibriú seo...", "Enter the public URL of your WebUI. This URL will be used to generate links in the notifications.": "Cuir isteach URL poiblí do WebUI. Bainfear úsáid as an URL seo chun naisc a ghiniúint sna fógraí.", "Enter the URL of the function to import": "Cuir isteach URL na feidhme atá le hallmhairiú", "Enter the URL to import": "Cuir isteach an URL le hallmhairiú", @@ -813,20 +830,24 @@ "Enter Your Username": "Cuir isteach D'Ainm Úsáideora", "Enter your webhook URL": "Cuir isteach URL do webhook", "Entra ID": "Aitheantas Entra", - "Environment Variables": "", - "Ephemeral": "", + "Environment Variables": "Athróga Timpeallachta", + "Ephemeral": "Gearrshaolach", "Error": "Earráid", "ERROR": "EARRÁID", "Error accessing directory": "Earráid ag rochtain eolaire", "Error accessing Google Drive: {{error}}": "Earráid agus tú ag rochtain Google Drive: {{error}}", "Error accessing media devices.": "Earráid ag rochtain gléasanna meán.", - "Error deleting model: {{error}}": "", + "Error deleting model: {{error}}": "Earráid ag scriosadh samhail: {{error}}", "Error starting recording.": "Earráid ag tosú taifeadta.", "Error unloading model: {{error}}": "Earráid ag díluchtú samhail: {{error}}", "Error uploading file: {{error}}": "Earráid agus comhad á uaslódáil: {{error}}", "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Earráid: Tá samhail leis an ID '{{modelId}}' ann cheana féin. Roghnaigh ID difriúil le dul ar aghaidh.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Earráid: Ní féidir ID an tSamhail a fhágáil folamh. Cuir isteach ID bailí le dul ar aghaidh.", "Evaluations": "Meastóireachtaí", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Eochair Exa API", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Sampla: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Sampla: GACH", @@ -838,25 +859,25 @@ "Execute code": "Cód a fhorghníomhú", "Execute code for analysis": "Íosluchtaigh cód le haghaidh anailíse", "Executing **{{NAME}}**...": "**{{NAME}}** á rith...", - "Execution Logs": "", + "Execution Logs": "Logaí Forghníomhaithe", "Expand": "Leathnaigh", "Experimental": "Turgnamhach", "Explain": "Mínigh", "Explore the cosmos": "Déan iniúchadh ar an cosmos", - "Explored": "", - "Exploring": "", + "Explored": "Iniúchadh", + "Exploring": "Ag iniúchadh", "Export": "Easpórtáil", "Export All Archived Chats": "Easpórtáil Gach Comhrá Cartlainne", "Export All Chats (All Users)": "Easpórtáil gach comhrá (Gach Úsáideoir)", - "Export as CSV": "", - "Export as JSON": "", + "Export as CSV": "Easpórtáil mar CSV", + "Export as JSON": "Easpórtáil mar JSON", "Export chat (.json)": "Easpórtáil comhrá (.json)", - "Export Chats": "Comhráite Easpórtá", - "Export Config": "Cumraíocht Easpórtála", - "Export Models": "Samhlacha Easpórtála", - "Export Prompts": "Leideanna Easpórtála", + "Export Chats": "Easpórtáil Comhráite", + "Export Config": "Easpórtáil Cumraíocht", + "Export Models": "Easpórtáil Samhlacha", + "Export Prompts": "Easpórtáil Treoracha", "Export to CSV": "Easpórtáil go CSV", - "Export Tools": "Uirlisí Easpórtála", + "Export Tools": "Easpórtáil Uirlisí", "Export Users": "Easpórtáil Úsáideoirí", "External": "Seachtrach", "External Document Loader URL required.": "URL Luchtaitheora Doiciméad Seachtrach ag teastáil.", @@ -868,13 +889,14 @@ "Fade Effect for Streaming Text": "Éifeacht Céimnithe le haghaidh Sruthú Téacs", "Failed to add file.": "Theip ar an gcomhad a chur leis.", "Failed to add members": "Theip ar bhaill a chur leis", - "Failed to archive chat.": "", + "Failed to archive chat.": "Theip ar an gcomhrá a chartlannú.", "Failed to attach file": "Theip ar an gcomhad a cheangal", "Failed to clear status": "Theip ar an stádas a ghlanadh", "Failed to connect to {{URL}} OpenAPI tool server": "Theip ar nascadh le {{URL}} freastalaí uirlisí OpenAPI", "Failed to connect to {{URL}} terminal server": "Theip ar cheangal le freastalaí críochfoirt {{URL}}", "Failed to copy link": "Theip ar an nasc a chóipeáil", "Failed to create API Key.": "Theip ar an eochair API a chruthú.", + "Failed to delete calendar": "", "Failed to delete note": "Theip ar an nóta a scriosadh", "Failed to download image": "Theip ar an íomhá a íoslódáil", "Failed to extract content from the file: {{error}}": "Theip ar an ábhar a bhaint as an gcomhad: {{error}}", @@ -883,11 +905,11 @@ "Failed to generate title": "Theip ar an teideal a ghiniúint", "Failed to import models": "Theip ar samhail a iompórtáil", "Failed to load chat preview": "Theip ar réamhamharc comhrá a lódáil", - "Failed to load DOCX file. Please try downloading it instead.": "", + "Failed to load DOCX file. Please try downloading it instead.": "Theip ar an gcomhad DOCX a luchtú. Déan iarracht é a íoslódáil ina ionad.", "Failed to load Excel/CSV file. Please try downloading it instead.": "Theip ar an gcomhad Excel/CSV a lódáil. Déan iarracht é a íoslódáil ina ionad.", "Failed to load file content.": "Theip ar lódáil ábhar an chomhaid.", "Failed to load Interface settings": "Theip ar shocruithe an Chomhéadain a lódáil", - "Failed to load PPTX file. Please try downloading it instead.": "", + "Failed to load PPTX file. Please try downloading it instead.": "Theip ar an gcomhad PPTX a luchtú. Déan iarracht é a íoslódáil ina ionad.", "Failed to move chat": "Theip ar an gcomhrá a bhogadh", "Failed to process URL: {{url}}": "Theip ar phróiseáil an URL: {{url}}", "Failed to read clipboard contents": "Theip ar ábhar gearrthaisce a lé", @@ -897,7 +919,7 @@ "Failed to save connections": "Theip ar na naisc a shábháil", "Failed to save conversation": "Theip ar an gcomhrá a shábháil", "Failed to save models configuration": "Theip ar chumraíocht na samhlacha a shábháil", - "Failed to save policy: {{error}}": "", + "Failed to save policy: {{error}}": "Theip ar an mbeartas a shábháil: {{error}}", "Failed to save terminal servers": "Theip ar fhreastalaithe críochfoirt a shábháil", "Failed to unshare chat.": "Theip ar an gcomhrá a dhíroinnt.", "Failed to update settings": "Theip ar shocruithe a nuashonrú", @@ -913,7 +935,7 @@ "Feedback History": "Stair Aiseolais", "Feel free to add specific details": "Ná bíodh leisce ort sonraí ar leith a chur leis", "Female": "Baineann", - "Fetch URL Content Length Limit": "", + "Fetch URL Content Length Limit": "Teorainn Fad Ábhar URL a Aisghabháil", "File": "Comhad", "File added successfully.": "D'éirigh leis an gcomhad a chur leis.", "File attached to chat": "Comhad ceangailte leis an gcomhrá", @@ -944,7 +966,7 @@ "Focus Chat Input": "Dírigh ar Ionchur Comhrá", "Folder": "Fillteán", "Folder Background Image": "Íomhá Chúlra Fillteáin", - "Folder created successfully": "", + "Folder created successfully": "Cruthaíodh fillteán go rathúil", "Folder deleted successfully": "Scriosadh an fillteán go rathúil", "Folder Max File Count": "Uasmhéid Líon Comhad Fillteán", "Folder name": "Ainm fillteáin", @@ -956,7 +978,7 @@ "Folders": "Fillteáin", "Follow up": "Leanúint suas", "Follow Up Generation": "Giniúint Leantach", - "Follow Up Generation Prompt": "Leid Ghiniúna Leanúnach", + "Follow Up Generation Prompt": "Treoir Giniúna Leantach", "Follow up: {{question}}": "Leanúint suas: {{question}}", "Follow-Up Auto-Generation": "Uathghiniúint Leantach", "Followed instructions perfectly": "Lean treoracha go foirfe", @@ -968,10 +990,10 @@ "Format Lines": "Formáid Línte", "Format the lines in the output. Defaults to False. If set to True, the lines will be formatted to detect inline math and styles.": "Formáidigh na línte san aschur. Is é Bréag an réamhshocrú. Má shocraítear é go Fíor, déanfar na línte a fhormáidiú chun matamaitic agus stíleanna inlíne a bhrath.", "Formatting may be inconsistent from source.": "B’fhéidir nach bhfuil an fhormáidiú comhsheasmhach ón bhfoinse.", - "Forward": "", + "Forward": "Ar Aghaidh", "Forwards system user OAuth access token to authenticate": "Seolann sé comhartha rochtana OAuth úsáideora an chórais ar aghaidh chun fíordheimhniú a dhéanamh", "Forwards system user session credentials to authenticate": "Cuir dintiúir seisiúin úsáideora córais ar aghaidh lena bhfíordheimhniú", - "Fr_day_of_week": "", + "Fr_day_of_week": "Aoine", "Full Context Mode": "Mód Comhthéacs Iomlán", "Function": "Feidhm", "Function Calling": "Glaonna Feidhme", @@ -1046,8 +1068,8 @@ "History": "Stair", "Home": "Baile", "Host": "Óstach", - "Hourly": "", - "Hourly Messages": "Teachtaireachtaí Uaireanta", + "Hourly": "Gach uair an chloig", + "Hourly Messages": "Teachtaireachtaí gach uair an chloig", "How can I help you today?": "Conas is féidir liom cabhrú leat inniu?", "How would you rate this response?": "Cad é mar a mheasfá an freagra seo?", "HTML": "HTML", @@ -1058,7 +1080,7 @@ "ID": "ID", "ID cannot contain \":\" or \"|\" characters": "Ní féidir carachtair \":\" nó \"|\" a bheith san ID", "ID copied to clipboard": "Aitheantas cóipeáilte chuig an ghearrthaisce", - "Idle Timeout": "", + "Idle Timeout": "Am Teorann Díomhaoin", "iframe Sandbox Allow Forms": "iframe Bosca Gainimh Foirmeacha Ceadaithe", "iframe Sandbox Allow Same Origin": "ceadaigh Bosca Gainimh iframe an Bunús Céanna", "Ignite curiosity": "Las fiosracht", @@ -1073,8 +1095,8 @@ "Image Max Compression Size": "Íomhá Méid Comhbhrú Max", "Image Max Compression Size height": "Airde Uasmhéid Comhbhrúite Íomhá", "Image Max Compression Size width": "Leithead Uasmhéid Comhbhrúite Íomhá", - "Image Prompt Generation": "Giniúint Leid Íomhá", - "Image Prompt Generation Prompt": "Leid Giniúint Leide Íomhá", + "Image Prompt Generation": "Giniúint Treoracha Íomhá", + "Image Prompt Generation Prompt": "Treoir Giniúna Treoracha Íomhá", "Image Size": "Méid na hÍomhá", "Images": "Íomhánna", "Import": "Iompórtáil", @@ -1082,7 +1104,7 @@ "Import Config": "Cumraíocht Iompórtála", "Import From Link": "Iompórtáil Ó Nasc", "Import Models": "Iompórtáil Samhlacha", - "Import Prompts": "Leideanna Iompórtála", + "Import Prompts": "Iompórtáil Treoracha", "Import successful": "D'éirigh leis an allmhairiú", "Import Tools": "Uirlisí Iompórtála", "Important Update": "Nuashonrú tábhachtach", @@ -1101,12 +1123,12 @@ "Input Key (e.g. text, unet_name, steps)": "Eochair Ionchuir (m.sh. téacs, unet_name, céimeanna)", "Input Variables": "Athróga Ionchuir", "Insert": "Cuir isteach", - "Insert Follow-Up Prompt to Input": "Cuir isteach leid leantach le hionchur", - "Insert Prompt as Rich Text": "Cuir isteach an leid mar théacs saibhir", - "Insert Suggestion Prompt to Input": "Cuir isteach Moladh Leid chun Ionchur", + "Insert Follow-Up Prompt to Input": "Cuir Treoir Leantach leis an Ionchur", + "Insert Prompt as Rich Text": "Cuir an Treoir isteach mar Théacs Saibhir", + "Insert Suggestion Prompt to Input": "Cuir Treoir Mholta leis an Ionchur", "Install from Github URL": "Suiteáil ó Github URL", "Instant Auto-Send After Voice Transcription": "Seoladh Uathoibríoch Láithreach Tar éis", - "Instructions": "", + "Instructions": "Treoracha", "Integration": "Comhtháthú", "Integrations": "Comhtháthúcháin", "Interface": "Comhéadan", @@ -1136,7 +1158,7 @@ "JWT Expiration": "Éag JWT", "JWT Token": "Comhartha JWT", "Kagi Search API Key": "Eochair API Chuardaigh Kagi", - "Keep Follow-Up Prompts in Chat": "Coinnigh Leideanna Leanúnacha i gComhrá", + "Keep Follow-Up Prompts in Chat": "Coinnigh Treoracha Leantacha sa Chomhrá", "Keep in Sidebar": "Coinnigh sa Bharra Taobh", "Key": "Eochair", "Key is required": "Tá eochair ag teastáil", @@ -1166,7 +1188,7 @@ "Last 90 days": "90 lá seo caite", "Last Active": "Gníomhach Deiridh", "Last Modified": "Athraithe Deiridh", - "Last ran": "", + "Last ran": "Rith dheireanach", "Last reply": "Freagra deiridh", "LDAP": "LDAP", "LDAP server updated": "Nuashonraíodh freastalaí LDAP", @@ -1186,7 +1208,7 @@ "Leave empty to use first admin user": "Fág folamh chun an chéad úsáideoir riarthóra a úsáid", "Leave empty to use the default config, or enter a valid json (see https://yandex.cloud/en/docs/search-api/api-ref/WebSearch/search#yandex.cloud.searchapi.v2.WebSearchRequest)": "Fág folamh chun an chumraíocht réamhshocraithe a úsáid, nó cuir isteach json bailí (féach https://yandex.cloud/en/docs/search-api/api-ref/WebSearch/search#yandex.cloud.searchapi.v2.WebSearchRequest)", "Leave empty to use the default model (voxtral-mini-latest).": "Fág folamh chun an tsamhail réamhshocraithe (voxtral-mini-latest) a úsáid.", - "Leave empty to use the default prompt, or enter a custom prompt": "Fág folamh chun an leid réamhshocraithe a úsáid, nó cuir isteach leid saincheaptha", + "Leave empty to use the default prompt, or enter a custom prompt": "Fág folamh chun an treoir réamhshocraithe a úsáid, nó cuir isteach treoir shaincheaptha", "Leave model field empty to use the default model.": "Fág an réimse samhail folamh chun an tsamhail réamhshocraithe a úsáid.", "Legacy": "Oidhreacht", "lexical": "leicseach", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Teorainn a chur le fiosrúcháin chuardaigh chomhuaineacha. 0 = gan teorainn (réamhshocraithe). Socraigh go 1 le haghaidh forghníomhú seicheamhach (molta do APIanna le teorainneacha ráta dochta cosúil le sraith saor in aisce Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Cuireann sé teorainn le líon na n-iarratas leabaithe comhuaineach. Socraigh go 0 le haghaidh neamhtheoranta.", "List": "Liosta", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Éisteacht...", "Live": "Beo", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "áitiúil", "Local": "Áitiúil", "Local Task Model": "Samhail Tasc Áitiúil", + "Location": "", "Location access not allowed": "Ní cheadaítear rochtain suímh", "Lost": "Cailleadh", "Low": "Íseal", @@ -1231,7 +1255,7 @@ "Max Speakers": "Uasmhéid Cainteoirí", "Max Upload Count": "Líon Uaslódála Max", "Max Upload Size": "Méid Uaslódála Max", - "Maximum characters to return from fetched URLs. Leave empty for no limit.": "", + "Maximum characters to return from fetched URLs. Leave empty for no limit.": "Uasmhéid carachtair le tabhairt ar ais ó URLanna a fuarthas. Fág folamh le haghaidh gan teorainn.", "Maximum number of files allowed per folder.": "Uasmhéid na gcomhad a cheadaítear in aghaidh an fhillteáin.", "Maximum number of files per folder is {{max}}.": "Is é {{max}} an líon uasta comhad in aghaidh an fhillteáin.", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Is féidir uasmhéid de 3 samhail a íoslódáil ag an am Bain triail as arís níos déanaí.", @@ -1263,25 +1287,27 @@ "Microsoft OneDrive": "Microsoft OneDrive", "Microsoft OneDrive (personal)": "Microsoft OneDrive (pearsanta)", "Microsoft OneDrive (work/school)": "Microsoft OneDrive (obair/scoil)", - "min": "", + "min": "nóim", "MinerU": "MinerU", "MinerU API Key required for Cloud API mode.": "Eochair API MinerU ag teastáil le haghaidh mód Cloud API.", "Mistral OCR": "OCR Mistral", "Mistral OCR API Key required.": "Mistral OCR API Eochair ag teastáil.", "MistralAI": "MistralAI", - "Mo_day_of_week": "", + "Mo_day_of_week": "Luan", "Model": "Samhail", "Model '{{modelName}}' has been successfully downloaded.": "Rinneadh an tsamhail '{{modelName}}' a íoslódáil go rathúil.", "Model '{{modelTag}}' is already in queue for downloading.": "Tá samhail '{{modelTag}}' sa scuaine cheana féin le híoslódáil.", - "Model {{modelName}} deleted successfully": "", + "Model {{modelId}} not found": "", + "Model {{modelName}} deleted successfully": "Scriosadh an tsamhail {{modelName}} go rathúil", "Model {{modelName}} is not vision capable": "Níl samhail {{modelName}} in ann amharc", "Model {{name}} is now {{status}}": "Tá samhail {{name}} {{status}} anois", "Model {{name}} is now hidden": "Tá an tsamhail {{name}} i bhfolach anois", "Model {{name}} is now visible": "Tá an tsamhail {{name}} le feiceáil anois", "Model accepts file inputs": "Glacann an tsamhail le hionchuir chomhaid", "Model accepts image inputs": "Glacann an tsamhail le hionchuir íomhá", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Is féidir leis an tsamhail cód a fhorghníomhú agus ríomhaireachtaí a dhéanamh", - "Model can generate images based on text prompts": "Is féidir leis an tsamhail íomhánna a ghiniúint bunaithe ar leideanna téacs", + "Model can generate images based on text prompts": "Is féidir leis an tsamhail íomhánna a ghiniúint bunaithe ar threoracha téacs", "Model can search the web for information": "Is féidir leis an tsamhail cuardach a dhéanamh ar an ngréasán le haghaidh faisnéise", "Model Capabilities": "Cumais Samhail", "Model created successfully!": "Cruthaíodh an tsamhail go rathúil!", @@ -1313,24 +1339,26 @@ "Models Sharing": "Roinnt Samhlacha", "Mojeek": "Mojeek", "Mojeek Search API Key": "Eochair API Cuardach Mojeek", - "Monthly": "", + "Month": "", + "Monthly": "Míosúil", "More": "Tuilleadh", "More Concise": "Níos Gonta", "More options": "Tuilleadh roghanna", "More Options": "Tuilleadh Roghanna", "Move": "Bog", - "Moved {{name}}": "", + "Moved {{name}}": "Bogadh {{name}}", "My Terminal": "Mo Teirminéal", "Name": "Ainm", "Name and ID are required, please fill them out": "Tá ainm agus aitheantas ag teastáil, líon isteach iad le do thoil", "Name your knowledge base": "Cuir ainm ar do bhunachar eolais", - "Name, prompt, and model are required": "", + "Name, prompt, and model are required": "Tá ainm, treoir agus samhail riachtanach", "Native": "Dúchasach", - "Never": "", + "Never": "Choíche", "New": "Nua", - "New Automation": "", + "New Automation": "Uathoibriú Nua", "New Button": "Cnaipe Nua", "New Chat": "Comhrá Nua", + "New Event": "", "New File": "Comhad Nua", "New Folder": "Fillteán Nua", "New Function": "Feidhm Nua", @@ -1339,7 +1367,7 @@ "New Model": "Samhail Nua", "New Note": "Nóta Nua", "New Password": "Pasfhocal Nua", - "New Prompt": "Leid Nua", + "New Prompt": "Treoir Nua", "New Skill": "Scil Nua", "New Temporary Chat": "Comhrá Sealadach Nua", "New Terminal": "Teirminéal Nua", @@ -1347,11 +1375,11 @@ "New Webhook": "Gréasáin Nua", "new-channel": "nua-chainéil", "Next message": "An chéad teachtaireacht eile", - "Next run": "", + "Next run": "An chéad rith eile", "No access grants. Private to you.": "Gan aon deontais rochtana. Príobháideach duitse.", "No activity data": "Gan aon sonraí gníomhaíochta", "No authentication": "Gan fíordheimhniú", - "No automations found": "", + "No automations found": "Níor aimsíodh aon uathoibrithe", "No chats found": "Ní bhfuarthas aon chomhráite", "No chats found for this user.": "Ní bhfuarthas aon chomhráite don úsáideoir seo.", "No chats found.": "Ní bhfuarthas aon chomhráite.", @@ -1362,22 +1390,22 @@ "No data": "Gan aon sonraí", "No data found": "Níor aimsíodh aon sonraí", "No distance available": "Níl achar ar fáil", - "No execution logs available yet": "", + "No execution logs available yet": "Níl aon logaí forghníomhaithe ar fáil go fóill", "No expiration can pose security risks.": "Ní féidir le haon dáta éaga rioscaí slándála a chruthú.", "No feedback found": "Níor aimsíodh aon aiseolas", "No file selected": "Níl aon chomhad roghnaithe", "No files found": "Níor aimsíodh aon chomhaid", "No files in this knowledge base.": "Níl aon chomhaid sa bhunachar eolais seo.", - "No files yet. Upload files or run Python code to create them.": "", + "No files yet. Upload files or run Python code to create them.": "Gan aon chomhaid fós. Uaslódáil comhaid nó rith cód Python chun iad a chruthú.", "No functions found": "Níor aimsíodh aon fheidhmeanna", "No groups found": "Níor aimsíodh aon ghrúpaí", "No history available": "Níl aon stair ar fáil", "No HTML, CSS, or JavaScript content found.": "Níor aimsíodh aon ábhar HTML, CSS nó JavaScript.", "No inference engine with management support found": "Níor aimsíodh aon inneall tátail le tacaíocht bhainistíochta", - "No kernel": "", + "No kernel": "Gan aon eithne", "No knowledge bases found.": "Níor aimsíodh aon bhunachair eolais.", "No knowledge found": "Níor aimsíodh aon eolas", - "No limit": "", + "No limit": "Gan teorainn", "No memories to clear": "Gan cuimhní cinn a ghlanadh", "No model IDs": "Gan aon aitheantóirí samhail", "No models available": "Níl aon samhlacha ar fáil", @@ -1387,15 +1415,15 @@ "No notes found": "Níor aimsíodh aon nótaí", "No one": "Níl aon duine", "No pinned messages": "Gan aon teachtaireachtaí bioráilte", - "No prompts found": "Níor aimsíodh aon leideanna", + "No prompts found": "Níor aimsíodh aon treoracha", "No results": "Níl aon torthaí le fáil", "No results found": "Níl aon torthaí le fáil", "No search query generated": "Ní ghintear aon cheist cuardaigh", - "No servers detected": "", + "No servers detected": "Níor braitheadh aon fhreastalaithe", "No skills found": "Níor aimsíodh aon scileanna", "No source available": "Níl aon fhoinse ar fáil", "No sources found": "Níor aimsíodh aon fhoinsí", - "No suggestion prompts": "Gan leideanna molta", + "No suggestion prompts": "Gan aon treoracha molta", "No Terminal connection configured.": "Gan nasc teirminéal cumraithe.", "No terminal connections configured.": "Gan aon naisc teirminéal cumraithe.", "No tool server connections configured.": "Níl aon naisc freastalaí uirlisí cumraithe.", @@ -1409,7 +1437,7 @@ "Not factually correct": "Níl sé ceart go fírineach", "Not helpful": "Gan a bheith cabhrach", "Not Registered": "Gan Clárú", - "Not scheduled": "", + "Not scheduled": "Gan sceidealú", "Note": "Nóta", "Note deleted successfully": "Scriosadh an nóta go rathúil", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Nóta: Má shocraíonn tú íosscór, ní thabharfaidh an cuardach ach doiciméid a bhfuil scór níos mó ná nó cothrom leis an scór íosta ar ais.", @@ -1422,7 +1450,7 @@ "November": "Samhain", "OAuth": "OAuth", "OAuth 2.1": "OAuth 2.1", - "OAuth 2.1 (Static)": "", + "OAuth 2.1 (Static)": "OAuth 2.1 (Statach)", "OAuth ID": "Aitheantas OAuth", "October": "Deireadh Fómhair", "Off": "As", @@ -1434,7 +1462,7 @@ "Ollama Cloud API Key": "Eochair API Ollama Cloud", "Ollama Version": "Leagan Ollama", "On": "Ar", - "Once": "", + "Once": "Uair amháin", "OneDrive": "OneDrive", "Only active when \"Paste Large Text as File\" setting is toggled on.": "Gníomhach amháin nuair a bhíonn an socrú \"Greamaigh Téacs Mór mar Chomhad\" casta air.", "Only active when the chat input is in focus and an LLM is generating a response.": "Gníomhach ach amháin nuair a bhíonn an t-ionchur comhrá i bhfócas agus nuair a bhíonn LLM ag giniúint freagra.", @@ -1453,7 +1481,7 @@ "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ups! Tá modh gan tacaíocht á úsáid agat (tosaigh amháin). Freastal ar an WebUI ón gcúltaca le do thoil.", "Open file": "Oscail comhad", "Open in full screen": "Oscail i scáileán iomlán", - "Open in new tab": "", + "Open in new tab": "Oscail i gcluaisín nua", "Open link": "Oscail nasc", "Open modal to configure connection": "Oscail an modal chun an nasc a chumrú", "Open Modal To Manage Floating Quick Actions": "Oscail Modúl Chun Gníomhartha Tapa Snámhacha a Bhainistiú", @@ -1484,7 +1512,7 @@ "or": "nó", "Ordered List": "Liosta Ordaithe", "Other": "Eile", - "out of": "", + "out of": "as", "Output": "Aschur", "OUTPUT": "ASCHUR", "Output format": "Formáid aschuir", @@ -1500,7 +1528,8 @@ "Password": "Pasfhocal", "Passwords do not match.": "Ní hionann na pasfhocail.", "Paste Large Text as File": "Greamaigh Téacs Mór mar Chomhad", - "Paused": "", + "Path copied": "", + "Paused": "Sosaithe", "PDF document (.pdf)": "Doiciméad PDF (.pdf)", "PDF Extract Images (OCR)": "Íomhánna Sliocht PDF (OCR)", "PDF Loader Mode": "Mód Luchtaithe PDF", @@ -1516,13 +1545,13 @@ "Perplexity Model": "Samhail Perplexity", "Perplexity Search API URL": "URL API Cuardaigh Measctha", "Perplexity Search Context Usage": "Úsáid Chomhthéacs Cuardaigh Mearbhall", - "Persistent": "", + "Persistent": "Dianseasmhach", "Personalization": "Pearsantú", "Pin": "Bioráin", "Pin to Sidebar": "", - "Pinned": "Pinneáilte", - "Pinned Messages": "Teachtaireachtaí Pionáilte", - "Pinned Models": "Samhlacha bioráilte", + "Pinned": "Bioránaithe", + "Pinned Messages": "Teachtaireachtaí Bioránaithe", + "Pinned Models": "Samhlacha Bioránaithe", "Pioneer insights": "Léargais ceannródaí", "Pipe": "Píopa", "Pipeline deleted successfully": "Scriosta píblíne go rathúil", @@ -1537,16 +1566,16 @@ "Playwright Timeout (ms)": "Teorainn Ama drámadóra (ms)", "Playwright WebSocket URL": "URL drámadóir WebSocket", "Please carefully review the following warnings:": "Déan athbhreithniú cúramach ar na rabhaidh seo a leanas le do thoil:", - "Please connect all required integrations before sending a message": "", + "Please connect all required integrations before sending a message": "Ceangail na comhtháthúcháin riachtanacha go léir sula seoltar teachtaireacht", "Please do not close the settings page while loading the model.": "Ná dún leathanach na socruithe agus an tsamhail á luchtú.", "Please enter a message or attach a file.": "Cuir isteach teachtaireacht nó ceangail comhad le do thoil.", - "Please enter a prompt": "Cuir isteach leid", + "Please enter a prompt": "Cuir isteach treoir", "Please enter a valid ID": "Cuir isteach aitheantas bailí le do thoil", "Please enter a valid JSON spec": "Cuir isteach sonraíocht JSON bhailí le do thoil", "Please enter a valid path": "Cuir isteach cosán bailí", "Please enter a valid URL": "Cuir isteach URL bailí", "Please enter a valid URL.": "Cuir isteach URL bailí le do thoil.", - "Please enter Client ID and Client Secret": "", + "Please enter Client ID and Client Secret": "Cuir isteach ID Cliant agus Rún Cliant le do thoil", "Please fill in all fields.": "Líon isteach gach réimse le do thoil.", "Please register the OAuth client": "Cláraigh an cliant OAuth le do thoil", "Please save the connection to persist the OAuth client information and do not change the ID": "Sábháil an nasc le go gcoimeádfar faisnéis an chliaint OAuth agus ná hathraigh an ID.", @@ -1556,9 +1585,9 @@ "Please select a valid JSON file": "Roghnaigh comhad JSON bailí le do thoil", "Please select at least one user for Direct Message channel.": "Roghnaigh úsáideoir amháin ar a laghad don chainéal Teachtaireachtaí Díreacha.", "Please wait until all files are uploaded.": "Fan go dtí go mbeidh na comhaid go léir uaslódáilte.", - "Policy ID": "", + "Policy ID": "Aitheantas Polasaí", "Port": "Port", - "Ports": "", + "Ports": "Poirt", "Positive attitude": "Dearcadh dearfach", "Prefer not to say": "Is fearr liom gan a rá", "Prefix ID": "Aitheantas Réimír", @@ -1572,29 +1601,29 @@ "Private conversation between selected users": "Comhrá príobháideach idir úsáideoirí roghnaithe", "Production version updated": "Leagan táirgeachta nuashonraithe", "Profile": "Próifíl", - "Prompt": "Leid", - "Prompt Autocompletion": "Uathchríochnú Pras", - "Prompt Content": "Ábhar Leid", - "Prompt created successfully": "Leid cruthaithe go rathúil", - "Prompt Name": "Ainm an Phraghas", - "Prompt Suggestions": "Moltaí Treoir", - "Prompt updated successfully": "D'éirigh leis an leid a nuashonrú", - "Prompts": "Leabhair", - "Prompts Access": "Rochtain ar Chuirí", - "Prompts Public Sharing": "Spreagann Roinnt Phoiblí", - "Prompts Sharing": "Comhroinnt Leideanna", + "Prompt": "Treoir", + "Prompt Autocompletion": "Uathchríochnú Treoracha", + "Prompt Content": "Ábhar na Treorach", + "Prompt created successfully": "Cruthaíodh an treoir go rathúil", + "Prompt Name": "Ainm na Treorach", + "Prompt Suggestions": "Moltaí Treoracha", + "Prompt updated successfully": "Nuashonraíodh an treoir go rathúil", + "Prompts": "Treoracha", + "Prompts Access": "Rochtain ar Threoracha", + "Prompts Public Sharing": "Comhroinnt Phoiblí Treoracha", + "Prompts Sharing": "Comhroinnt Treoracha", "Provider Type": "Cineál Soláthraí", "Public": "Poiblí", "Pull \"{{searchValue}}\" from Ollama.com": "Tarraing \"{{searchValue}}\" ó Ollama.com", "Pull a model from Ollama.com": "Tarraing samhail ó Ollama.com", "Pull Model": "Samhail Tarraingthe", - "Pyodide file browser": "", - "Query Generation Prompt": "Cuirí Ginearáil Ceisteanna", + "Pyodide file browser": "Brabhsálaí comhad Pyodide", + "Query Generation Prompt": "Treoir Giniúna Ceisteanna", "Querying": "Ag fiosrú", "Quick Actions": "Gníomhartha Tapa", "RAG Template": "Teimpléad RAG", - "Ran {{COUNT}} analyses": "", - "Ran {{COUNT}} analysis": "", + "Ran {{COUNT}} analyses": "Rinne {{COUNT}} anailísí", + "Ran {{COUNT}} analysis": "Rinneadh anailís ar {{COUNT}}", "Rate {{rating}} out of 10": "Rátáil {{rating}} as 10", "Rating": "Rátáil", "Re-rank models by topic similarity": "Athrangú samhlacha de réir cosúlachta topaice", @@ -1606,7 +1635,8 @@ "Reason": "Cúis", "Reasoning Effort": "Iarracht Réasúnúcháin", "Reasoning Tags": "Clibeanna Réasúnaíochta", - "Recently Used": "", + "Recently Used": "Úsáidte le Déanaí", + "Reconnected": "", "Record": "Taifead", "Record voice": "Taifead guth", "Redirecting you to Open WebUI Community": "Tú a atreorú chuig OpenWebUI Community", @@ -1630,6 +1660,7 @@ "Relevance": "Ábharthacht", "Relevance Threshold": "Tairseach Ábharthaíochta", "Remember Dismissal": "Cuimhnigh ar an Dífhostú", + "Reminder": "", "Remove": "Bain", "Remove {{MODELID}} from list.": "Bain {{MODELID}} den liosta.", "Remove action": "Bain gníomh", @@ -1639,15 +1670,16 @@ "Remove image": "Bain íomhá", "Remove Model": "Bain an tSamhail", "Rename": "Athainmnigh", - "Renamed to {{name}}": "", + "Renamed to {{name}}": "Athainmnithe go {{name}}", "Render Markdown in Previews": "Rindreáil Markdown i Réamhamhairc", "Reorder Models": "Athordú na Samhlacha", - "Repeats": "", + "Repeats": "Athdhéantar", "Reply": "Freagra", "Reply in Thread": "Freagra i Snáithe", "Reply to thread...": "Freagra ar an snáithe...", "Replying to {{NAME}}": "Ag freagairt do {{NAME}}", "required": "riachtanach", + "Reranking Batch Size": "", "Reranking Engine": "Inneall Athrangúcháin", "Reranking Model": "Samhail Athrangú", "Reset": "Athshocraigh", @@ -1663,7 +1695,7 @@ "Responses": "Freagraí", "Restart": "", "Result": "Toradh", - "RESULT": "Toradh", + "RESULT": "TORADH", "Retrieval": "Aisghabháil", "Retrieval Query Generation": "Aisghabháil Giniúint Ceist", "Retrieved {{count}} sources": "Aisghafa {{count}} foinsí", @@ -1674,13 +1706,13 @@ "Role": "Ról", "RTL": "RTL", "Run": "Rith", - "Run All": "", - "Run now": "", - "Run Now": "", + "Run All": "Rith Gach Rud", + "Run now": "Rith anois", + "Run Now": "Rith Anois", "Running": "Ag rith", "Running...": "Ag rith...", "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "Ritheann sé tascanna leabaithe ag an am céanna chun luas a chur leis an bpróiseáil. Múch é má bhíonn teorainneacha ráta ina bhfadhb.", - "Sa_day_of_week": "", + "Sa_day_of_week": "Satharn", "Save": "Sábháil", "Save & Create": "Sábháil & Cruthaigh", "Save & Update": "Sábháil & Nuashonraigh", @@ -1688,15 +1720,15 @@ "Save Chat": "Sábháil Comhrá", "Saved": "Shábháil", "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "Ní thacaítear le logaí comhrá a shábháil go díreach chuig stóráil do bhrabhsálaí Tóg nóiméad chun do logaí comhrá a íoslódáil agus a scriosadh trí chliceáil an cnaipe thíos. Ná bíodh imní ort, is féidir leat do logaí comhrá a athiompórtáil go héasca chuig an gcúltaca trí", - "Schedule": "", - "Scheduled time must be in the future": "", + "Schedule": "Sceideal", + "Scheduled time must be in the future": "Ní mór don am sceidealaithe a bheith sa todhchaí", "Scroll On Branch Change": "Scrollaigh ar Athrú Brainse", "Search": "Cuardaigh", "Search a model": "Cuardaigh samhail", "Search all emojis": "Cuardaigh gach emoji", "Search and manage user memories": "Cuardaigh agus bainistigh cuimhní úsáideora", "Search and view user chat history": "Cuardaigh agus féach ar stair comhrá úsáideora", - "Search Automations": "", + "Search Automations": "Uathoibriúcháin Cuardaigh", "Search Base": "Bonn Cuardaigh", "Search channels and channel messages": "Cuardaigh bealaí agus teachtaireachtaí bealaí", "Search Chats": "Cuardaigh Comhráite", @@ -1712,11 +1744,11 @@ "Search Groups": "Cuardaigh Grúpaí", "Search In Models": "Cuardaigh i Samhlacha", "Search Knowledge": "Cuardaigh Eolais", - "Search Memories": "", + "Search Memories": "Cuardaigh Cuimhní", "Search Models": "Cuardaigh Samhlacha", "Search Notes": "Cuardaigh Nótaí", "Search options": "Roghanna cuardaigh", - "Search Prompts": "Leideanna Cuardaigh", + "Search Prompts": "Treoracha Cuardaigh", "Search Result Count": "Líon Torthaí Cuardaigh", "Search Skills": "Scileanna Cuardaigh", "Search the internet": "Cuardaigh an tIdirlíon", @@ -1754,7 +1786,7 @@ "Select a theme": "Roghnaigh téama", "Select a tool": "Roghnaigh uirlis", "Select a voice": "Roghnaigh guth", - "Select All": "", + "Select All": "Roghnaigh Uile", "Select an auth method": "Roghnaigh modh an údair", "Select an embedding model engine": "Roghnaigh inneall samhail leabaithe", "Select an engine": "Roghnaigh inneall", @@ -1766,7 +1798,7 @@ "Select how to split message text for TTS requests": "Roghnaigh conas téacs teachtaireachta a roinnt le haghaidh iarratais TTS", "Select Knowledge": "Roghnaigh Eolais", "Select Method": "Roghnaigh Modh", - "Select model": "", + "Select model": "Roghnaigh samhail", "Select only one model to call": "Roghnaigh samhail amháin le glaoch", "Select view": "Roghnaigh radharc", "Selected model: {{modelName}}": "Samhail roghnaithe: {{modelName}}", @@ -1784,7 +1816,7 @@ "Serper API Key": "Serper API Eochair", "Serply API Key": "Eochair API Serply", "Serpstack API Key": "Eochair API Serpstack", - "Server connection failed": "", + "Server connection failed": "Theip ar cheangal leis an bhfreastalaí", "Server connection verified": "Ceangal freastalaí fíoraithe", "Session": "Seisiún", "Set as default": "Socraigh mar réamhshocraithe", @@ -1802,7 +1834,7 @@ "Sets a flat bias against tokens that have appeared at least once. A higher value (e.g., 1.5) will penalize repetitions more strongly, while a lower value (e.g., 0.9) will be more lenient. At 0, it is disabled.": "Socraíonn sé claonadh cothrom i gcoinne comharthaí a tháinig chun solais uair amháin ar a laghad. Cuirfidh luach níos airde (m.sh., 1.5) pionós níos láidre ar athrá, agus beidh luach níos ísle (m.sh., 0.9) níos boige. Ag 0, tá sé díchumasaithe.", "Sets a scaling bias against tokens to penalize repetitions, based on how many times they have appeared. A higher value (e.g., 1.5) will penalize repetitions more strongly, while a lower value (e.g., 0.9) will be more lenient. At 0, it is disabled.": "Socraíonn sé laofacht scálaithe i gcoinne comharthaí chun pionós a ghearradh ar athrá, bunaithe ar cé mhéad uair a tháinig siad chun solais. Cuirfidh luach níos airde (m.sh., 1.5) pionós níos láidre ar athrá, agus beidh luach níos ísle (m.sh., 0.9) níos boige. Ag 0, tá sé díchumasaithe.", "Sets how far back for the model to look back to prevent repetition.": "Socraíonn sé cé chomh fada siar is atá an tsamhail le breathnú siar chun athrá a chosc.", - "Sets the random number seed to use for generation. Setting this to a specific number will make the model generate the same text for the same prompt.": "Socraíonn sé an síol uimhir randamach a úsáid le haghaidh giniúna. Má shocraítear é seo ar uimhir shainiúil, ginfidh an tsamhail an téacs céanna don leid céanna.", + "Sets the random number seed to use for generation. Setting this to a specific number will make the model generate the same text for the same prompt.": "Socraíonn sé an síol uimhir randamach a úsáid le haghaidh giniúna. Má shocraítear é seo ar uimhir shainiúil, ginfidh an tsamhail an téacs céanna don treoir céanna.", "Sets the size of the context window used to generate the next token.": "Socraíonn sé méid na fuinneoige comhthéacs a úsáidtear chun an chéad chomhartha eile a ghiniúint.", "Sets the stop sequences to use. When this pattern is encountered, the LLM will stop generating text and return. Multiple stop patterns may be set by specifying multiple separate stop parameters in a modelfile.": "Socraíonn sé na stadanna le húsáid. Nuair a thagtar ar an bpatrún seo, stopfaidh an LLM ag giniúint téacs agus ag filleadh. Is féidir patrúin stad iolracha a shocrú trí pharaiméadair stadanna iolracha a shonrú i gcomhad samhail.", "Setting": "Socrú", @@ -1875,8 +1907,12 @@ "Start a new conversation": "Tosaigh comhrá nua", "Start of the channel": "Tús an chainéil", "Start Tag": "Clib Tosaigh", - "Starting kernel...": "", - "State": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", + "Starting kernel...": "Ag tosú an eithne...", + "Starting now": "", + "State": "Stát", "Status": "Stádas", "Status cleared successfully": "Glanadh an stádais go rathúil", "Status updated successfully": "Nuashonraíodh an stádas go rathúil", @@ -1887,7 +1923,7 @@ "Stop Download": "Stop an Íoslódáil", "Stop Generating": "Stop a Ghiniúint", "Stop Sequence": "Stop Seicheamh", - "Storage": "", + "Storage": "Stóráil", "Stream Chat Response": "Freagra Comhrá Sruth", "Stream Delta Chunk Size": "Sruth Méid Leadhb Delta", "Streamable HTTP": "HTTP sruthaithe", @@ -1897,7 +1933,7 @@ "STT Model": "Samhail STT", "STT Settings": "Socruithe STT", "Stylized PDF Export": "Easpórtáil PDF Stílithe", - "Su_day_of_week": "", + "Su_day_of_week": "Domhnaigh", "Submit question": "Cuir ceist isteach", "Submit suggestion": "Cuir moladh isteach", "Subtitle": "Fotheideal", @@ -1919,19 +1955,19 @@ "Syncs only chats with updates after your last sync timestamp. Disable to re-sync all chats.": "Ní shioncrónaíonn sé ach comhráite le nuashonruithe tar éis do stampa ama sioncrónaithe deireanach. Díchumasaigh chun gach comhrá a athshioncrónú.", "System": "Córas", "System Instructions": "Treoracha Córas", - "System Prompt": "Córas Leid", + "System Prompt": "Treoir Chóras", "Tag": "Clib", "Tags": "Clibeanna", "Tags Generation": "Giniúint Clibeanna", - "Tags Generation Prompt": "Clibeanna Giniúint Leid", + "Tags Generation Prompt": "Treoir Giniúna Clibeanna", "Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting.": "Úsáidtear sampláil saor ó eireabaill chun tionchar na n-chomharthaí ón aschur nach bhfuil chomh dóchúil céanna a laghdú. Laghdóidh luach níos airde (m.sh., 2.0) an tionchar níos mó, agus díchumasaíonn luach 1.0 an socrú seo. (réamhshocraithe: 1)", "Talk to Model": "Labhair leis an tSamhail", "Tap to interrupt": "Tapáil chun cur isteach", "Task List": "Liosta Tascanna", - "Task Management": "", - "Task Model": "Samhail Thasc", + "Task Management": "Bainistíocht Tascanna", + "Task Model": "Samhail Tasc", "Tasks": "Tascanna", - "tasks completed": "", + "tasks completed": "tascanna críochnaithe", "Tavily API Key": "Eochair API Tavily", "Tavily Extract Depth": "Doimhneacht Sliocht Tavily", "Tell us more:": "Inis dúinn níos mó:", @@ -1943,7 +1979,7 @@ "Text Splitter": "Scoilteoir Téacs", "Text-to-Speech": "Téacs-go-Caint", "Text-to-Speech Engine": "Inneall téacs-go-labhra", - "Th_day_of_week": "", + "Th_day_of_week": "Déardaoin", "Thanks for your feedback!": "Go raibh maith agat as do chuid aiseolas!", "The Application Account DN you bind with for search": "An Cuntas Feidhmchláir DN a nascann tú leis le haghaidh cuardaigh", "The base to search for users": "An bonn chun cuardach a dhéanamh ar úsáideoirí", @@ -1988,9 +2024,10 @@ "This will delete {{NAME}} and all its contents.": "Scriosfaidh sé seo {{NAME}} agus a bhfuil ann go léir.", "This will delete all models including custom models": "Scriosfaidh sé seo gach samhail lena n-áirítear samhlacha saincheaptha", "This will delete all models including custom models and cannot be undone.": "Scriosfaidh sé seo gach samhail, lena n-áirítear samhlacha saincheaptha, agus ní féidir é a chealú.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Déanfaidh sé seo an bonn eolais a athshocrú agus gach comhad a shioncronú. Ar mhaith leat leanúint ar aghaidh?", "Thorough explanation": "Míniú críochnúil", - "Thought": "", + "Thought": "Smaoineamh", "Thought for {{DURATION}}": "Smaoineamh ar {{DURATION}}", "Thought for {{DURATION}} seconds": "Smaoineamh ar feadh {{DURATION}} soicind", "Thought for less than a second": "Smaoinigh mé ar feadh níos lú ná soicind", @@ -1999,14 +2036,15 @@ "Tika": "Tika", "Tika Server URL required.": "Teastaíonn URL Freastalaí Tika.", "Tiktoken": "Tiktoken", - "Time": "", + "Time": "Am", "Time & Calculation": "Am & Ríomh", "Timeout": "Am istigh", "Title": "Teideal", "Title Auto-Generation": "Teideal Auto-Generation", "Title cannot be an empty string.": "Ní féidir leis an teideal a bheith ina teaghrán folamh.", "Title Generation": "Giniúint Teidil", - "Title Generation Prompt": "Leid Giniúint Teideal", + "Title Generation Prompt": "Treoir Giniúna Teidil", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Chun rochtain a fháil ar ainmneacha na samhlacha atá ar fáil lena n-íoslódáil,", "To access the GGUF models available for downloading,": "Chun rochtain a fháil ar na samhlacha GGUF atá ar fáil lena n-íoslódáil,", @@ -2017,11 +2055,11 @@ "To select toolkits here, add them to the \"Tools\" workspace first.": "Chun trealamh uirlisí a roghnú anseo, cuir iad leis an spás oibre \"Uirlisí\" ar dtús.", "Toast notifications for new updates": "Fógraí tósta le haghaidh nuashonruithe nua", "Today": "Inniu", - "Today at": "", + "Today at": "Inniu ag", "Today at {{LOCALIZED_TIME}}": "Inniu ag {{LOCALIZED_TIME}}", "Toggle {{COUNT}} sources": "Athraigh {{COUNT}} foinsí", "Toggle 1 source": "Athraigh foinse amháin", - "Toggle details": "", + "Toggle details": "Athraigh sonraí", "Toggle Dictation": "Athraigh Deachtú", "Toggle Sidebar": "Barra Taobh a Athraigh", "Toggle status history": "Athraigh stair stádais", @@ -2042,7 +2080,7 @@ "Tools": "Uirlisí", "Tools Access": "Rochtain Uirlisí", "Tools are a function calling system with arbitrary code execution": "Is córas glaonna feidhme iad uirlisí le forghníomhú cód treallach", - "Tools Function Calling Prompt": "Leid Glaonna Feidhm Uirlisí", + "Tools Function Calling Prompt": "Treoir Ghlao Feidhme Uirlisí", "Tools have a function calling system that allows arbitrary code execution.": "Tá córas glaonna feidhme ag uirlisí a cheadaíonn forghníomhú cód treallach.", "Tools Public Sharing": "Uirlisí Roinnte Poiblí", "Tools Sharing": "Comhroinnt Uirlisí", @@ -2057,7 +2095,7 @@ "TTS Model": "Samhail TTS", "TTS Settings": "Socruithe TTS", "TTS Voice": "Guth TTS", - "Tu_day_of_week": "", + "Tu_day_of_week": "Máirt", "Type": "Cineál", "Type here...": "Clóscríobh anseo...", "Type Hugging Face Resolve (Download) URL": "Cineál Hugging Face Resolve (Íoslódáil) URL", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "Díluchtuithe {{FROM_NOW}}", "Unlock mysteries": "Díghlasáil rúndiamhra", "Unpin": "Díphoráil", + "Unpin from Sidebar": "", "Unravel secrets": "Rúin a réiteach", "Unshare Chat": "Díroinn Comhrá", "Unsupported file type.": "Cineál comhaid nach dtacaítear leis.", @@ -2106,7 +2145,7 @@ "URL Mode": "Mód URL", "Usage": "Úsáid", "Use": "Úsáid", - "Use '#' in the prompt input to load and include your knowledge.": "Úsáid '#' san ionchur leid chun do chuid eolais a lódáil agus a chur san áireamh.", + "Use '#' in the prompt input to load and include your knowledge.": "Úsáid '#' san ionchur treoir chun do chuid eolais a lódáil agus a chur san áireamh.", "Use /v1/chat/completions endpoint instead of /v1/audio/transcriptions for potentially better accuracy.": "Bain úsáid as an gcríochphointe /v1/chat/completions in ionad /v1/audio/transcriptions le haghaidh cruinneas níos fearr b’fhéidir.", "Use Chat Completions API": "Úsáid API Comhlánuithe Comhrá", "Use groups to organize your users and assign permissions.": "Bain úsáid as grúpaí chun d’úsáideoirí a eagrú agus ceadanna a shannadh.", @@ -2152,15 +2191,15 @@ "Voice": "Guth", "Voice Input": "Ionchur Gutha", "Voice mode": "Mod Gutha", - "Voice Mode Custom Prompt": "Leid Saincheaptha Mód Gutha", - "Voice Mode Prompt": "Leid Mód Gutha", + "Voice Mode Custom Prompt": "Treoir Saincheaptha Mód Gutha", + "Voice Mode Prompt": "Treoir Mód Gutha", "Waiting for upload...": "Ag fanacht le huaslódáil...", "Warning": "Rabhadh", "Warning:": "Rabhadh:", - "Warning: Enabling this will allow users to run scheduled prompts automatically.": "", + "Warning: Enabling this will allow users to run scheduled prompts automatically.": "Rabhadh: Trí seo a chumasú, beidh úsáideoirí in ann leideanna sceidealaithe a rith go huathoibríoch.", "Warning: Enabling this will allow users to upload arbitrary code on the server.": "Rabhadh: Cuirfidh sé seo ar chumas úsáideoirí cód treallach a uaslódáil ar an bhfreastalaí.", "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "Rabhadh: Trí fhorghníomhú Jupyter is féidir cód a fhorghníomhú go treallach, rud a chruthaíonn mór-rioscaí slándála - bí fíorchúramach.", - "We_day_of_week": "", + "We_day_of_week": "Céadaoin", "Web": "Gréasán", "Web API": "API Gréasáin", "Web Loader Engine": "Inneall Luchtaithe Gréasáin", @@ -2177,13 +2216,15 @@ "WebUI will make requests to \"{{url}}\"": "Déanfaidh WebUI iarratais ar \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "Déanfaidh WebUI iarratais ar \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "Déanfaidh WebUI iarratais ar \"{{url}}/chat/completions\"", - "Weekly": "", + "Week": "", + "Weekly": "Seachtainiúil", "What are you trying to achieve?": "Cad atá tú ag iarraidh a bhaint amach?", "What are you working on?": "Cad air a bhfuil tú ag obair?", "What is NOT shared:": "Cad NACH roinntear", "What is shared:": "Cad a roinntear:", "What's New in": "Cad atá Nua i", "What's on your mind?": "Cad atá ar d’intinn?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Nuair a bheidh sé cumasaithe, freagróidh an tsamhail gach teachtaireacht comhrá i bhfíor-am, ag giniúint freagra a luaithe a sheolann an t-úsáideoir teachtaireacht. Tá an mód seo úsáideach le haghaidh feidhmchláir chomhrá beo, ach d'fhéadfadh tionchar a bheith aige ar fheidhmíocht ar chrua-earraí níos moille.", "wherever you are": "aon áit a bhfuil tú", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Cibé acu an ndéanfar an t-aschur a roinnt le leathanaigh nó nach ndéanfar. Beidh riail chothrománach agus uimhir leathanaigh ag scartha ó gach leathanach. Is é Bréag an rogha réamhshocraithe.", @@ -2194,14 +2235,14 @@ "Width": "Leithead", "Wikipedia": "Vicipéid", "Won": "Bhuaigh", - "Working Directory": "", + "Working Directory": "Eolaire Oibre", "Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text.": "Oibríonn sé le barr-k. Beidh téacs níos éagsúla mar thoradh ar luach níos airde (m.sh., 0.95), agus ginfidh luach níos ísle (m.sh., 0.5) téacs níos dírithe agus níos coimeádaí.", "Workspace": "Spás oibre", "Workspace Permissions": "Ceadanna Spás Oibre", "Write": "Scríobh", "Write a summary in 50 words that summarizes {{topic}}.": "Scríobh achoimre i 50 focal a dhéanann achoimre ar [ábhar nó eochairfhocal].", "Write something...": "Scríobh rud...", - "Write your model system prompt content here\ne.g.) You are Mario from Super Mario Bros, acting as an assistant.": "Scríobh inneachar system prompt do mhúnla anseo\nm.sh.: Is é Mario ó Super Mario Bros tú agus tá tú ag gníomhú mar chúntóir.", + "Write your model system prompt content here\ne.g.) You are Mario from Super Mario Bros, acting as an assistant.": "Scríobh inneachar threoir chórais do mhúnla anseo\nm.sh.: Is é Mario ó Super Mario Bros tú, ag gníomhú mar chúntóir.", "Yacy Instance URL": "URL Cás Yacy", "Yacy Password": "Pasfhocal Yacy", "Yacy Username": "Ainm úsáideora Yacy", @@ -2218,7 +2259,7 @@ "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Is féidir leat do chuid idirghníomhaíochtaí le LLManna a phearsantú ach cuimhní cinn a chur leis tríd an gcnaipe 'Bainistigh' thíos, rud a fhágann go mbeidh siad níos cabhrach agus níos oiriúnaí duit.", "You cannot upload an empty file.": "Ní féidir leat comhad folamh a uaslódáil.", "You do not have permission to edit this model": "Níl cead agat an tsamhail seo a chur in eagar", - "You do not have permission to edit this prompt.": "Níl cead agat an leid seo a chur in eagar.", + "You do not have permission to edit this prompt.": "Níl cead agat an treoir seo a chur in eagar.", "You do not have permission to edit this skill.": "Níl cead agat an scil seo a chur in eagar.", "You do not have permission to edit this tool": "Níl cead agat an uirlis seo a chur in eagar", "You do not have permission to make this public": "Níl cead agat é seo a chur ar fáil don phobal", @@ -2235,8 +2276,8 @@ "You're now logged in.": "Tá tú logáilte isteach anois.", "Your Account": "Do Chuntas", "Your account status is currently pending activation.": "Tá stádas do chuntais ar feitheamh faoi ghníomhachtú.", - "Your browser does not support the audio tag.": "", - "Your browser does not support the video tag.": "", + "Your browser does not support the audio tag.": "Ní thacaíonn do bhrabhsálaí leis an gclib fuaime.", + "Your browser does not support the video tag.": "Ní thacaíonn do bhrabhsálaí leis an gclib físeáin.", "Your entire contribution will go directly to the plugin developer; Open WebUI does not take any percentage. However, the chosen funding platform might have its own fees.": "Rachaidh do ranníocaíocht iomlán go díreach chuig an bhforbróir breiseán; Ní ghlacann Open WebUI aon chéatadán. Mar sin féin, d'fhéadfadh a tháillí féin a bheith ag an ardán maoinithe roghnaithe.", "Your message text or inputs": "Téacs nó ionchur do theachtaireachta", "Your usage stats have been successfully synced.": "Tá do staitisticí úsáide sioncronaithe go rathúil.", diff --git a/src/lib/i18n/locales/it-IT/translation.json b/src/lib/i18n/locales/it-IT/translation.json index 8cb9822986..c94b0f7f5a 100644 --- a/src/lib/i18n/locales/it-IT/translation.json +++ b/src/lib/i18n/locales/it-IT/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "{{user}} Chat", "{{webUIName}} Backend Required": "{{webUIName}} Richiesta Backend", "*Prompt node ID(s) are required for image generation": "*ID nodo prompt sono necessari per la generazione di immagini", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Una nuova versione (v{{LATEST_VERSION}}) è ora disponibile.", @@ -48,6 +53,7 @@ "Access Control": "Controllo accessi", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Accessibile a tutti gli utenti", "Account": "Account", "Account Activation Pending": "Account in attesa di attivazione", @@ -73,9 +79,11 @@ "Add content here": "Aggiungi un contenuto qui", "Add Custom Parameter": "Aggiungi Parametri Personalizzati", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Aggiungi dei file", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Aggiungi memoria", @@ -111,6 +119,7 @@ "AI": "", "All": "Tutti", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Tutti i modelli eliminati con successo", @@ -199,6 +208,7 @@ "Ask a question": "Fai una domanda", "Assistant": "Assistente", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -273,6 +283,8 @@ "Bypass Web Loader": "Bypassa il Web Loader", "Cache Base Model List": "", "Calendar": "Calendario", + "Calendar deleted": "", + "Calendars": "", "Call": "Chiamata", "Call feature is not supported when using Web STT engine": "La funzione di chiamata non è supportata quando si utilizza il motore Web STT", "Camera": "Fotocamera", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Connettiti ai tuoi server di tool esterni compatibili con OpenAPI.", "Connected ({{type}})": "", "Connection failed": "Connessione fallita", + "Connection lost. Reconnecting...": "", "Connection successful": "Connessione riuscita", "Connection Type": "Tipo Connessione", "Connections": "Connessioni", @@ -440,6 +453,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Copia link", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Copia negli appunti", @@ -520,8 +534,11 @@ "Delete All Chats": "Elimina tutte le chat", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Elimina chat", "Delete chat?": "Elimina chat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Elimina cartella?", "Delete function?": "Elimina funzione?", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Valutazioni", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Chiave API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Esempio: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Esempio: TUTTI", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Impossibile copiare il link", "Failed to create API Key.": "Impossibile creare Chiave API.", + "Failed to delete calendar": "", "Failed to delete note": "Impossibile eliminare la nota", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "In ascolto...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1230,7 @@ "local": "", "Local": "Locale", "Local Task Model": "Modello Task locale", + "Location": "", "Location access not allowed": "Accesso alla posizione non consentito", "Lost": "Perso", "Low": "", @@ -1274,6 +1298,7 @@ "Model": "Modello", "Model '{{modelName}}' has been successfully downloaded.": "Il modello '{{modelName}}' è stato scaricato con successo.", "Model '{{modelTag}}' is already in queue for downloading.": "Il modello '{{modelTag}}' è già in coda per il download.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Il modello {{modelName}} non è in grado di vedere", "Model {{name}} is now {{status}}": "Il modello {{name}} è ora {{status}}", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "Il modello {{name}} è ora visibile", "Model accepts file inputs": "Tipo ti file accettati dal modello", "Model accepts image inputs": "Il modello accetta input immagine", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Il modello può eseguire del codice e fare calcoli", "Model can generate images based on text prompts": "Il modello può generare delle immagini basate sui prompt testuali", "Model can search the web for information": "Il modello può cercare nella rete per informazioni", @@ -1314,6 +1340,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Chiave API di Mojeek Search", + "Month": "", "Monthly": "", "More": "Altro", "More Concise": "", @@ -1332,6 +1359,7 @@ "New Automation": "", "New Button": "", "New Chat": "Nuova chat", + "New Event": "", "New File": "", "New Folder": "Nuova cartella", "New Function": "", @@ -1501,6 +1529,7 @@ "Password": "Password", "Passwords do not match.": "", "Paste Large Text as File": "Incolla Molto Testo come File", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Documento PDF (.pdf)", "PDF Extract Images (OCR)": "Estrazione Immagini PDF (OCR)", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "Sforzo di ragionamento", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Registra", "Record voice": "Registra voce", "Redirecting you to Open WebUI Community": "Reindirizzamento alla comunità OpenWebUI", @@ -1631,6 +1661,7 @@ "Relevance": "Rilevanza", "Relevance Threshold": "Soglia di Rilevanza", "Remember Dismissal": "", + "Reminder": "", "Remove": "Rimuovi", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1649,6 +1680,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "Engine di Riclassificazione", "Reranking Model": "Modello di Riclassificazione", "Reset": "Ripristina", @@ -1877,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "Inizio del canale", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Questa opzione eliminerà {{NAME}} e tutti i suoi contenuti.", "This will delete all models including custom models": "Questa opzione eliminerà tutti i modelli, compresi i modelli personalizzati", "This will delete all models including custom models and cannot be undone.": "Questa opzione eliminerà tutti i modelli, compresi i modelli personalizzati e non può essere annullata.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Questa opzione ripristinerà la base di conoscenza e sincronizzerà tutti i file. Vuoi continuare?", "Thorough explanation": "Spiegazione dettagliata", "Thought": "", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "Il titolo non può essere una stringa vuota.", "Title Generation": "Generazione del titolo", "Title Generation Prompt": "Prompt di generazione del titolo", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Per accedere ai nomi dei modelli disponibili per il download,", "To access the GGUF models available for downloading,": "Per accedere ai modelli GGUF disponibili per il download,", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Scarica {{FROM_NOW}}", "Unlock mysteries": "Sblocca misteri", "Unpin": "Rimuovi fissato", + "Unpin from Sidebar": "", "Unravel secrets": "Svela segreti", "Unshare Chat": "", "Unsupported file type.": "", @@ -2179,6 +2219,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI farà richieste a \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI farà richieste a \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI farà richieste a \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Cosa stai cercando di ottenere?", "What are you working on?": "Su cosa stai lavorando?", @@ -2186,6 +2227,7 @@ "What is shared:": "", "What's New in": "Novità in", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Quando abilitato, il modello risponderà a ciascun messaggio della chat in tempo reale, generando una risposta non appena l'utente invia un messaggio. Questa modalità è utile per le applicazioni di chat dal vivo, ma potrebbe influire sulle prestazioni su hardware più lento.", "wherever you are": "Ovunque tu sia", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Specifica se paginare l'output. Ogni pagina sarà separata da una riga orizzontale e dal numero di pagina. Predefinito è Falso.", diff --git a/src/lib/i18n/locales/ja-JP/translation.json b/src/lib/i18n/locales/ja-JP/translation.json index be5c8d6a98..af0c4211b5 100644 --- a/src/lib/i18n/locales/ja-JP/translation.json +++ b/src/lib/i18n/locales/ja-JP/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "{{user}} のチャット", "{{webUIName}} Backend Required": "{{webUIName}} バックエンドが必要です", "*Prompt node ID(s) are required for image generation": "*画像生成にはプロンプトノードIDが必要です", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "新しいバージョン (v{{LATEST_VERSION}}) が利用可能です。", @@ -46,6 +51,7 @@ "Access Control": "アクセス権制御", "Access Grants": "", "Access List": "アクセス権リスト", + "Access updated": "", "Accessible to all users": "すべてのユーザーにアクセス可能", "Account": "アカウント", "Account Activation Pending": "アカウント承認待ち", @@ -71,9 +77,11 @@ "Add content here": "ここへコンテンツを追加", "Add Custom Parameter": "カスタムパラメータを追加", "Add Custom Prompt": "カスタムプロンプトを追加", + "Add description": "", "Add Details": "より詳しく", "Add Files": "ファイルを追加", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "メモリを追加", @@ -109,6 +117,7 @@ "AI": "AI", "All": "全て", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "全てのモデルが正常に削除されました", @@ -197,6 +206,7 @@ "Ask a question": "質問する", "Assistant": "アシスタント", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "ナレッジからファイルを添付", "Attach Files": "ファイルを追加", "Attach Knowledge": "ナレッジを追加", @@ -271,6 +281,8 @@ "Bypass Web Loader": "Webローダーをバイパス", "Cache Base Model List": "ベースモデルリストをキャッシュ", "Calendar": "カレンダー", + "Calendar deleted": "", + "Calendars": "", "Call": "コール", "Call feature is not supported when using Web STT engine": "Web STTエンジンを使用している場合、コール機能は使用できません", "Camera": "カメラ", @@ -407,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "独自のOpenAPI互換外部ツールサーバーに接続します。", "Connected ({{type}})": "", "Connection failed": "接続に失敗しました", + "Connection lost. Reconnecting...": "", "Connection successful": "接続に成功しました", "Connection Type": "接続タイプ", "Connections": "接続", @@ -438,6 +451,7 @@ "Copy Last Response": "直前の応答をコピー", "Copy link": "リンクをコピー", "Copy Link": "リンクをコピー", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "クリップボードにコピー", @@ -518,8 +532,11 @@ "Delete All Chats": "すべてのチャットを削除", "Delete all contents inside this folder": "", "Delete automation?": "オートメーションを削除しますか?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "チャットを削除", "Delete chat?": "チャットを削除しますか?", + "Delete Event": "", "Delete File": "", "Delete folder?": "フォルダーを削除しますか?", "Delete function?": "Functionを削除しますか?", @@ -826,6 +843,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "ID '{{modelId}}' のモデルはすでに存在します。他のIDを使用してください。", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "モデルIDを空にすることはできません。有効なIDを入力してください。", "Evaluations": "評価", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa APIキー", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "例: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "例: ALL", @@ -874,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "リンクのコピーに失敗しました。", "Failed to create API Key.": "APIキーの作成に失敗しました。", + "Failed to delete calendar": "", "Failed to delete note": "ノートの削除に失敗しました。", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "ファイルから中身の取得に失敗しました: {{error}}", @@ -1195,6 +1217,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "リスト", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "聞いています...", "Live": "", "Llama.cpp": "", @@ -1205,6 +1228,7 @@ "local": "", "Local": "ローカル", "Local Task Model": "ローカルタスクモデル", + "Location": "", "Location access not allowed": "位置情報のアクセスが許可されていません", "Lost": "負け", "Low": "低", @@ -1272,6 +1296,7 @@ "Model": "モデル", "Model '{{modelName}}' has been successfully downloaded.": "モデル '{{modelName}}' が正常にダウンロードされました。", "Model '{{modelTag}}' is already in queue for downloading.": "モデル '{{modelTag}}' はすでにダウンロード待機中です。", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "モデル {{modelName}} は視覚に対応していません", "Model {{name}} is now {{status}}": "モデル {{name}} は {{status}} になりました。", @@ -1279,6 +1304,7 @@ "Model {{name}} is now visible": "モデル {{name}} は表示されました。", "Model accepts file inputs": "モデルはファイル入力を受け入れます", "Model accepts image inputs": "モデルは画像入力を受け入れます", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "モデルはコードを実行し、計算を行うことができます", "Model can generate images based on text prompts": "モデルはテキストプロンプトに基づいて画像を生成できます", "Model can search the web for information": "モデルは情報をウェブ検索できます", @@ -1312,6 +1338,7 @@ "Models Sharing": "モデルの共有", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search APIキー", + "Month": "", "Monthly": "", "More": "もっと見る", "More Concise": "より簡潔に", @@ -1330,6 +1357,7 @@ "New Automation": "新しいオートメーション", "New Button": "新しいボタン", "New Chat": "新しいチャット", + "New Event": "", "New File": "", "New Folder": "新しいフォルダ", "New Function": "新しいFunction", @@ -1499,6 +1527,7 @@ "Password": "パスワード", "Passwords do not match.": "パスワードが一致しません。", "Paste Large Text as File": "大きなテキストをファイルとして貼り付ける", + "Path copied": "", "Paused": "停止中", "PDF document (.pdf)": "PDF ドキュメント (.pdf)", "PDF Extract Images (OCR)": "PDF 画像抽出 (OCR)", @@ -1606,6 +1635,7 @@ "Reasoning Effort": "推理の努力", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "録音", "Record voice": "音声を録音", "Redirecting you to Open WebUI Community": "OpenWebUI コミュニティにリダイレクトしています", @@ -1629,6 +1659,7 @@ "Relevance": "関連性", "Relevance Threshold": "関連性の閾値", "Remember Dismissal": "閉じたことを記憶する", + "Reminder": "", "Remove": "削除", "Remove {{MODELID}} from list.": "{{MODELID}} をリストから削除する", "Remove action": "", @@ -1647,6 +1678,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "リランクエンジン", "Reranking Model": "リランクモデル", "Reset": "リセット", @@ -1873,7 +1905,10 @@ "Start a new conversation": "新しい会話を開始", "Start of the channel": "チャンネルの開始", "Start Tag": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "状態", "Status": "ステータス", "Status cleared successfully": "正常にステータスをクリアしました", @@ -1986,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "これは{{NAME}}とそのすべての内容を削除します。", "This will delete all models including custom models": "これはカスタムモデルを含むすべてのモデルを削除します", "This will delete all models including custom models and cannot be undone.": "これはカスタムモデルを含むすべてのモデルを削除し、元に戻すことはできません。", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "これは知識ベースをリセットし、すべてのファイルを同期します。続けますか?", "Thorough explanation": "詳細な説明", "Thought": "", @@ -2005,6 +2041,7 @@ "Title cannot be an empty string.": "タイトルは空文字列にできません。", "Title Generation": "タイトル生成", "Title Generation Prompt": "タイトル生成プロンプト", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "ダウンロード可能なモデル名にアクセスするには、", "To access the GGUF models available for downloading,": "ダウンロード可能な GGUF モデルにアクセスするには、", @@ -2071,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}}にアンロード", "Unlock mysteries": "ミステリーを解き明かす", "Unpin": "ピン留め解除", + "Unpin from Sidebar": "", "Unravel secrets": "秘密を解き明かす", "Unshare Chat": "", "Unsupported file type.": "未対応のファイルタイプです", @@ -2175,6 +2213,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUIは\"{{url}}\"にリクエストを行います", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUIは\"{{url}}/api/chat\"にリクエストを行います", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUIは\"{{url}}/chat/completions\"にリクエストを行います", + "Week": "", "Weekly": "", "What are you trying to achieve?": "何を達成したいですか?", "What are you working on?": "何に取り組んでいますか?", @@ -2182,6 +2221,7 @@ "What is shared:": "", "What's New in": "新機能", "What's on your mind?": "今の状況を入力してください", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "有効にすると、ユーザのメッセージ送信と同時にリアルタイムで応答を生成します。ライブチャット用途に適しますが、性能の低い環境では動作が重くなる可能性があります。", "wherever you are": "どこにいても", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "出力をページ分けするかどうか。各ページは水平線とページ番号で分割されます。デフォルトでは無効", diff --git a/src/lib/i18n/locales/ka-GE/translation.json b/src/lib/i18n/locales/ka-GE/translation.json index cdbc392315..acdc14db3c 100644 --- a/src/lib/i18n/locales/ka-GE/translation.json +++ b/src/lib/i18n/locales/ka-GE/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}-ის ჩათები", "{{webUIName}} Backend Required": "{{webUIName}} საჭიროა უკანაბოლო", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "1 წყარო", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "ხელმისაწვდომია ახალი ვერსია (v{{LATEST_VERSION}}).", @@ -47,6 +52,7 @@ "Access Control": "წვდომის კონტროლი", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "ხელმისაწვდომია ყველა მომხმარებლისთვის", "Account": "ანგარიში", "Account Activation Pending": "დარჩენილი ანგარიშის აქტივაცია", @@ -72,9 +78,11 @@ "Add content here": "შემცველობის აქ დამატება", "Add Custom Parameter": "მორგებული პარამეტრის დამატება", "Add Custom Prompt": "", + "Add description": "", "Add Details": "დეტალების დამატება", "Add Files": "ფაილების დამატება", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "მეხსიერების დამატება", @@ -110,6 +118,7 @@ "AI": "AI", "All": "ყველა", "All chats have been unarchived.": "ყველა ჩატი ამოღებული იქნა არქივიდან.", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "ყველა მოდელი წარმატებით წაიშალა", @@ -198,6 +207,7 @@ "Ask a question": "კითხვის დასმა", "Assistant": "დამხმარე", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "ცოდნის მიმაგრება", @@ -272,6 +282,8 @@ "Bypass Web Loader": "ვებჩამტვირთავის გამოტოვება", "Cache Base Model List": "საბაზისო მოდელების სიის დაკეშვა", "Calendar": "კალენდარი", + "Calendar deleted": "", + "Calendars": "", "Call": "ზარი", "Call feature is not supported when using Web STT engine": "", "Camera": "კამერა", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "დაკავშირება ვერ მოხერხდა", + "Connection lost. Reconnecting...": "", "Connection successful": "შეერთება წარმატებულია", "Connection Type": "შეერთების ტიპი", "Connections": "კავშირები", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "ბმულის კოპირება", "Copy Link": "ბმულის კოპირება", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "ბუფერში კოპირება", @@ -519,8 +533,11 @@ "Delete All Chats": "ყველა ჩატის წაშლა", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "საუბრის წაშლა", "Delete chat?": "წავშალო ჩატი?", + "Delete Event": "", "Delete File": "", "Delete folder?": "წავშალო საქაღალდეები?", "Delete function?": "წავშალო ფუნქცია?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "შეფასებები", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API-ის გასაღები", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "მაგალითი: ALL", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "ბმულის კოპირება ჩავარდა", "Failed to create API Key.": "API-ის გასაღების შექმნა ჩავარდა.", + "Failed to delete calendar": "", "Failed to delete note": "შენიშვნის წაშლა ჩავარდა", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "ვისმენ...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "", "Local": "ლოკალური", "Local Task Model": "ლოკალური დავალების მოდელი", + "Location": "", "Location access not allowed": "მდებარეობასთან წვდომა დაშვებული არაა", "Lost": "წაგება", "Low": "დაბალი", @@ -1273,6 +1297,7 @@ "Model": "მოდელი", "Model '{{modelName}}' has been successfully downloaded.": "მოდელის „{{modelName}}“ გადმოწერა წარმატებით დასრულდა.", "Model '{{modelTag}}' is already in queue for downloading.": "მოდელი „{{modelTag}}“ უკვე გადმოწერის რიგშია.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Model {{modelName}} is not vision capable", "Model {{name}} is now {{status}}": "Model {{name}} is now {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "მოდელი {{name}} ახლა ხილულია", "Model accepts file inputs": "მოდელი იღებს ფაილებს", "Model accepts image inputs": "მოდელი იღებს გამოსახულებებს", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "მოდელს შეუძლია კოდის გაშვება და გამოთვლების შესრულება", "Model can generate images based on text prompts": "მოდელს შეუძლია ტექსტის მიხედვით გამოსახულებების გენერაცია", "Model can search the web for information": "მოდელს შეუძლია ინტერნეტში ინფორმაციის ძებნა", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "მეტი", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "ახალი ღილაკი", "New Chat": "ახალი მიმოწერა", + "New Event": "", "New File": "", "New Folder": "ახალი საქაღალდე", "New Function": "ახალი ფუნქცია", @@ -1500,6 +1528,7 @@ "Password": "პაროლი", "Passwords do not match.": "პაროლები არ ემთხვევა.", "Paste Large Text as File": "დიდი ტექსტის ჩასმა ფაილის სახით", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF დოკუმენტი (.pdf)", "PDF Extract Images (OCR)": "PDF იდან ამოღებული სურათები (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "ჩაწერა", "Record voice": "ხმის ჩაწერა", "Redirecting you to Open WebUI Community": "მიმდინარეობს გადამისამართება OpenWebUI-ის საზოგადოების საიტზე", @@ -1630,6 +1660,7 @@ "Relevance": "შესაბამისობა", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "წაშლა", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "აუცილებელია", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Reranking მოდელი", "Reset": "ჩამოყრა", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "არხის დასაწყისი", "Start Tag": "დაწყების ჭდე", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "საფუძვლიანი ახსნა", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "სათაურის ველი ცარიელი სტრიქონი ვერ იქნება.", "Title Generation": "სათაურის გენერაცია", "Title Generation Prompt": "სათაურის შექმნის მოთხოვნა", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "ხელმისაწვდომი მოდელის სახელებთან წვდომისთვის, რომ გადმოწეროთ,", "To access the GGUF models available for downloading,": "გადმოსაწერად ხელმისაწვდომი GGUF მოდელებზე წვდომისთვის,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "გამოტვირთვა {{FROM_NOW}}", "Unlock mysteries": "", "Unpin": "ჩამოხსნა", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "რას ცდილობთ, მიაღწიოთ?", "What are you working on?": "რაზე მუშაობთ?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "რა არის ახალი", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "სადაც არ უნდა ბრძანდებოდეთ", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/kab-DZ/translation.json b/src/lib/i18n/locales/kab-DZ/translation.json index 82dcd4c833..0fc3787813 100644 --- a/src/lib/i18n/locales/kab-DZ/translation.json +++ b/src/lib/i18n/locales/kab-DZ/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "Asqerdec n {{user}}", "{{webUIName}} Backend Required": "", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "1 n weɣbalu", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Lqem amaynut n (v{{LATEST_VERSION}}), yella akka tura.", @@ -47,6 +52,7 @@ "Access Control": "Asenqed n unekcum", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Yella i yiseqdacen i meṛṛa", "Account": "Amiḍan", "Account Activation Pending": "Armad n umiḍan deg uṛaǧu", @@ -72,9 +78,11 @@ "Add content here": "Rnu agbur da", "Add Custom Parameter": "Rnu aɣewwar udmawan", "Add Custom Prompt": "", + "Add description": "", "Add Details": "Rnu talqayt", "Add Files": "Rnu ifuyla", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Rnu cfawat", @@ -110,6 +118,7 @@ "AI": "TT", "All": "Akk", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Akk timudmiwin ttwakksent akken iwata", @@ -198,6 +207,7 @@ "Ask a question": "Efk-d asteqsi", "Assistant": "Amallal", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "Qqen-as tamessunt", @@ -272,6 +282,8 @@ "Bypass Web Loader": "Zgel asalay Web", "Cache Base Model List": "Ffer tabdart n tmudmiwin n taffa", "Calendar": "Awitay", + "Calendar deleted": "", + "Calendars": "", "Call": "Siwel", "Call feature is not supported when using Web STT engine": "Tamahilt n usiwel ur tettwasefrak ara mi ara tesqedceḍ amsedday Web STT", "Camera": "Takamiṛatt", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Qqen ɣer yiqeddacen-ik n yifecka imeṛṛa yeldin.", "Connected ({{type}})": "", "Connection failed": "Tuqqna d-tawezɣit", + "Connection lost. Reconnecting...": "", "Connection successful": "Tuqqna tedda akken iwata", "Connection Type": "Anaw n tuqqna", "Connections": "Tuqqniwin", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "Nɣel aseɣwen", "Copy Link": "Nɣel aseɣwen", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Nɣel ɣef afus", @@ -519,8 +533,11 @@ "Delete All Chats": "Kkes akk idiwenniyen", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Kkes asqerdec", "Delete chat?": "Tebɣiḍ ad tekkseḍ adiwenni?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Kkes akaram?", "Delete function?": "Kkes tasɣent?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Iktazalen", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Tasarut API n Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Amedya: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Amedya: AKK", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Ur yessaweḍ ara ad yessukken aseɣwen", "Failed to create API Key.": "Ur yessaweḍ ara ad d-yesnulfu tasarut API.", + "Failed to delete calendar": "", "Failed to delete note": "Ur yessaweḍ ara ad yekkes tazmilt", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Ur yessaweḍ ara ad d-yekkes agbur seg ufaylu: {{error}}", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Yettmaḥsis…", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "", "Local": "Adigan", "Local Task Model": "Tamudemt n temsekrit tadigant", + "Location": "", "Location access not allowed": "Anekcum ɣer tuddna", "Lost": "Iruḥ", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "Tamudemt", "Model '{{modelName}}' has been successfully downloaded.": "Tettwasider-d tmudemt '{{modelName}}' akken iwata.", "Model '{{modelTag}}' is already in queue for downloading.": "Tamudemt '{{modelTag}}' ha-t-an yakan deg tebdart n usader.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Mudel Isem}} mačči d tamuɣli izemren ad tili", "Model {{name}} is now {{status}}": "Tamudemt {{name}} tura {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "Tamudemt {{name}} tettbin-d tura", "Model accepts file inputs": "Mudell iqebbel inekcamen n yifuyla", "Model accepts image inputs": "Mudell iqebbel inekcamen n tugna", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Mudell yezmer ad d-yesseḍru tangalt u ad yexdem leḥsabat", "Model can generate images based on text prompts": "Ammud yezmer ad d-yawi tugniwin yebnan ɣef teɣratin n yiḍrisen", "Model can search the web for information": "Tamudemt-a tezmer ad tnadi deg Web ɣef isallen", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Tasarut API n Mojeek", + "Month": "", "Monthly": "", "More": "Ugar", "More Concise": "Awezlan ugar", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "Taqeffalt tamaynut", "New Chat": "Asqerdec amaynut", + "New Event": "", "New File": "", "New Folder": "Akaram amaynut", "New Function": "Tasɣent tamaynut", @@ -1500,6 +1528,7 @@ "Password": "Awal n uɛeddi", "Passwords do not match.": "Awalen n uɛeddi ur mṣadan ara.", "Paste Large Text as File": "Senteḍ aḍris meqqren am ufaylu", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Isemli PDF (.pdf)", "PDF Extract Images (OCR)": "Tugniwin n ugemmay PDF", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Aklas", "Record voice": "Sekles taɣect", "Redirecting you to Open WebUI Community": "Aseḍfeṛ ar Temɣiwant n Open WebUI", @@ -1630,6 +1660,7 @@ "Relevance": "Tawatit", "Relevance Threshold": "", "Remember Dismissal": "Ccfawa ɣef ugdal", + "Reminder": "", "Remove": "Kkes", "Remove {{MODELID}} from list.": "Kkes {{MODELID}} seg wumuɣ.", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "Err i udiwenni…", "Replying to {{NAME}}": "Tiririt i {{NAME}}", "required": "yettwasra", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "", "Reset": "Wennez", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Tazwara n ubadu", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Aya ad yekkes {NAME}} akked akk ayen yellan deg-s.", "This will delete all models including custom models": "Aya ad yekkes akk timudmin yellan gar-asent timudmin n tannumi", "This will delete all models including custom models and cannot be undone.": "Aya ad yekkes akk timudmin gar-asent timudmin tudmawanin yerna ur yezmir yiwen ad tent-id-yerr.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Aya ad yales taffa n tmussni u ad yemtawi akk ifuyla. Tebɣiḍ ad tkemmleḍ?", "Thorough explanation": "Asegzi leqqayen", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Azwel ur yettili ara d azrir ilem.", "Title Generation": "Asirew n uzwel", "Title Generation Prompt": "Aneftaɣ n usirew n uzwel", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Akken ad tkecmeḍ ɣer yismawen n tmudmiwin yellan i uzdam,", "To access the GGUF models available for downloading,": "Akken ad tkecmeḍ ɣer tmudmin GGUF yellan i usader,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "Kkes asenteḍ", + "Unpin from Sidebar": "", "Unravel secrets": "Sban-d ayen yeffren", "Unshare Chat": "", "Unsupported file type.": "Tawsit n ufaylu ur tettusefrak ara.", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI ad ssutreɣ \"{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI ad ssutreɣ i \"{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI ad ssutreɣ i \"{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Sanda ay tettarmed ad tessiwḍed?", "What are you working on?": "Ɣef wacu ay la tettmahaled?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "D acu d amaynut deg", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "anda yebɣu tiliḍ", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Ma tebɣiḍ ad d-tessugneḍ tuffɣa. Yal asebter ad yebḍu s ulugen igli d wuṭṭun n usebter. Imezwura ɣer False.", diff --git a/src/lib/i18n/locales/ko-KR/translation.json b/src/lib/i18n/locales/ko-KR/translation.json index 96a52e359d..e29c402508 100644 --- a/src/lib/i18n/locales/ko-KR/translation.json +++ b/src/lib/i18n/locales/ko-KR/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "{{user}}의 채팅", "{{webUIName}} Backend Required": "{{webUIName}} 백엔드가 필요합니다.", "*Prompt node ID(s) are required for image generation": "이미지 생성에는 프롬프트 노드 ID가 필요합니다.", + "1 hour before": "", "1 Source": "소스1", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "새로운 버전 (v{{LATEST_VERSION}})을 사용할 수 있습니다.", @@ -46,6 +51,7 @@ "Access Control": "접근 제어", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "모든 사용자가 이용할 수 있음", "Account": "계정", "Account Activation Pending": "계정 활성화 대기", @@ -71,9 +77,11 @@ "Add content here": "여기에 내용을 추가하세요", "Add Custom Parameter": "사용자 정의 매개변수 추가", "Add Custom Prompt": "사용자 정의 프롬프트 추가", + "Add description": "", "Add Details": "디테일 추가", "Add Files": "파일 추가", "Add Image": "", + "Add location": "", "Add Member": "멤버 추가", "Add Members": "멤버 추가", "Add Memory": "메모리 추가", @@ -109,6 +117,7 @@ "AI": "", "All": "전체", "All chats have been unarchived.": "모든 채팅이 보관 해제되었습니다.", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "성공적으로 모든 모델이 삭제되었습니다", @@ -197,6 +206,7 @@ "Ask a question": "질문하기", "Assistant": "어시스턴트", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "지식 기반에서 파일 첨부", "Attach Files": "", "Attach Knowledge": "지식 기반 첨부", @@ -271,6 +281,8 @@ "Bypass Web Loader": "웹 콘텐츠 불러오기 생략", "Cache Base Model List": "기본 모델 목록 캐시", "Calendar": "캘린더", + "Calendar deleted": "", + "Calendars": "", "Call": "음성 기능", "Call feature is not supported when using Web STT engine": "웹 STT 엔진 사용 시, 음성 기능은 지원되지 않습니다.", "Camera": "카메라", @@ -407,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "OpenAPI 호환 외부 도구 서버에 연결합니다.", "Connected ({{type}})": "", "Connection failed": "연결 실패", + "Connection lost. Reconnecting...": "", "Connection successful": "연결 성공", "Connection Type": "연결 방식", "Connections": "연결", @@ -438,6 +451,7 @@ "Copy Last Response": "마지막 응답 복사", "Copy link": "링크 복사", "Copy Link": "링크 복사", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "클립보드에 복사", @@ -518,8 +532,11 @@ "Delete All Chats": "모든 채팅 삭제", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "채팅 삭제", "Delete chat?": "채팅을 삭제하시겠습니까?", + "Delete Event": "", "Delete File": "", "Delete folder?": "폴더를 삭제하시겠습니까?", "Delete function?": "함수를 삭제하시겠습니까?", @@ -826,6 +843,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "평가", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API 키", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "예: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "예: 전체", @@ -874,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "링크 복사 실패", "Failed to create API Key.": "API 키 생성에 실패했습니다.", + "Failed to delete calendar": "", "Failed to delete note": "노트 삭제 실패", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "파일 내용 추출 실패: {{error}}", @@ -1195,6 +1217,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "듣는 중...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1205,6 +1228,7 @@ "local": "", "Local": "로컬", "Local Task Model": "로컬 작업 모델", + "Location": "", "Location access not allowed": "위치 접근이 허용되지 않습니다", "Lost": "패배", "Low": "", @@ -1272,6 +1296,7 @@ "Model": "모델", "Model '{{modelName}}' has been successfully downloaded.": "모델 '{{modelName}}'이/가 성공적으로 다운로드되었습니다.", "Model '{{modelTag}}' is already in queue for downloading.": "모델 '{{modelTag}}'은/는 이미 다운로드 대기열에 있습니다.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "모델 {{modelName}}은/는 비전을 사용할 수 없습니다.", "Model {{name}} is now {{status}}": "모델 {{name}}은/는 이제 {{status}} 상태입니다.", @@ -1279,6 +1304,7 @@ "Model {{name}} is now visible": "모델 {{name}}은/는 이제 볼 수 있습니다.", "Model accepts file inputs": "모델에 파일 입력을 허용합니다", "Model accepts image inputs": "모델에 이미지 입력을 허용합니다", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "모델이 코드를 실행하고 계산을 수행할 수 있습니다.", "Model can generate images based on text prompts": "모델이 텍스트 프롬프트를 기반으로 이미지를 생성할 수 있습니다.", "Model can search the web for information": "모델이 웹에서 정보를 검색할 수 있습니다.", @@ -1312,6 +1338,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API 키", + "Month": "", "Monthly": "", "More": "더보기", "More Concise": "더 간결하게", @@ -1330,6 +1357,7 @@ "New Automation": "", "New Button": "새 버튼", "New Chat": "새 채팅", + "New Event": "", "New File": "", "New Folder": "새 폴더", "New Function": "새 함수", @@ -1499,6 +1527,7 @@ "Password": "비밀번호", "Passwords do not match.": "비밀번호가 일치하지 않습니다.", "Paste Large Text as File": "큰 텍스트를 파일로 붙여넣기", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF 문서(.pdf)", "PDF Extract Images (OCR)": "PDF 이미지 추출(OCR)", @@ -1606,6 +1635,7 @@ "Reasoning Effort": "추론 난이도", "Reasoning Tags": "추론 태그", "Recently Used": "", + "Reconnected": "", "Record": "녹음", "Record voice": "음성 녹음", "Redirecting you to Open WebUI Community": "OpenWebUI 커뮤니티로 리디렉션 중", @@ -1629,6 +1659,7 @@ "Relevance": "관련도", "Relevance Threshold": "관련성 임계값", "Remember Dismissal": "다시 보지 않기", + "Reminder": "", "Remove": "삭제", "Remove {{MODELID}} from list.": "{{MODELID}}를 목록에서 제거.", "Remove action": "", @@ -1647,6 +1678,7 @@ "Reply to thread...": "스레드로 답장하기...", "Replying to {{NAME}}": "{{NAME}}에게 답장하는 중", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "Reranking 엔진", "Reranking Model": "Reranking 모델", "Reset": "초기화", @@ -1873,7 +1905,10 @@ "Start a new conversation": "새 대화 시작", "Start of the channel": "채널 시작", "Start Tag": "시작 태그", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "상태", "Status cleared successfully": "상태 초기화에 성공했습니다", @@ -1986,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "{{NAME}}모든 내용을 삭제합니다.", "This will delete all models including custom models": "이렇게 하면 사용자 지정 모델을 포함한 모든 모델이 삭제됩니다", "This will delete all models including custom models and cannot be undone.": "이렇게 하면 사용자 지정 모델을 포함한 모든 모델이 삭제되며 실행 취소할 수 없습니다.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "지식 기반과 모든 파일 연동을 초기화합니다. 계속 하시겠습니까?", "Thorough explanation": "완전한 설명", "Thought": "", @@ -2005,6 +2041,7 @@ "Title cannot be an empty string.": "제목은 빈 문자열일 수 없습니다.", "Title Generation": "제목 생성", "Title Generation Prompt": "제목 생성 프롬프트", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "다운로드 가능한 모델명을 확인하려면,", "To access the GGUF models available for downloading,": "다운로드 가능한 GGUF 모델을 확인하려면,", @@ -2071,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} 언로드", "Unlock mysteries": "미스터리 풀기", "Unpin": "고정 해제", + "Unpin from Sidebar": "", "Unravel secrets": "비밀 풀기", "Unshare Chat": "", "Unsupported file type.": "지원하지 않는 파일 형식", @@ -2175,6 +2213,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI가 \"{{url}}\"로 요청을 보냅니다", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI가 \"{{url}}/api/chat\"로 요청을 보냅니다", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI가 \"{{url}}/chat/completions\"로 요청을 보냅니다", + "Week": "", "Weekly": "", "What are you trying to achieve?": "무엇을 성취하고 싶으신가요?", "What are you working on?": "어떤 작업을 하고 계신가요?", @@ -2182,6 +2221,7 @@ "What is shared:": "", "What's New in": "새로운 기능:", "What's on your mind?": "무슨 생각을 하고 계신가요?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "활성화하면 모델이 각 채팅 메시지에 실시간으로 응답하여 사용자가 메시지를 보내는 즉시 응답을 생성합니다. 이 모드는 실시간 채팅 애플리케이션에 유용하지만, 느린 하드웨어에서는 성능에 영향을 미칠 수 있습니다.", "wherever you are": "당신이 어디에 있든", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "출력을 페이지로 나눌지 여부입니다. 각 페이지는 구분선과 페이지 번호로 구분됩니다. 기본값은 False입니다.", diff --git a/src/lib/i18n/locales/lt-LT/translation.json b/src/lib/i18n/locales/lt-LT/translation.json index 87819d1d2e..784832cde7 100644 --- a/src/lib/i18n/locales/lt-LT/translation.json +++ b/src/lib/i18n/locales/lt-LT/translation.json @@ -35,8 +35,13 @@ "{{user}}'s Chats": "{{user}} susirašinėjimai", "{{webUIName}} Backend Required": "{{webUIName}} būtinas serveris", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -49,6 +54,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "Paskyra", "Account Activation Pending": "Laukiama paskyros patvirtinimo", @@ -74,9 +80,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Pridėti failus", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Pridėti atminį", @@ -112,6 +120,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -200,6 +209,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -274,6 +284,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "Skambinti", "Call feature is not supported when using Web STT engine": "Skambučio funkcionalumas neleidžiamas naudojant Web STT variklį", "Camera": "Kamera", @@ -410,6 +422,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Ryšiai", @@ -441,6 +454,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Kopijuoti nuorodą", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -521,8 +535,11 @@ "Delete All Chats": "Ištrinti visus pokalbius", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Ištrinti pokalbį", "Delete chat?": "Ištrinti pokalbį?", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "Ištrinti funkciją", @@ -829,6 +846,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -877,6 +898,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Nepavyko sukurti API rakto", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1198,6 +1220,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Klausoma...", "Live": "", "Llama.cpp": "", @@ -1208,6 +1231,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1275,6 +1299,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "'{{modelName}}' modelis sėkmingai atsisiųstas.", "Model '{{modelTag}}' is already in queue for downloading.": "Modelis '{{modelTag}}' jau atsisiuntimų eilėje.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Modelis {{modelName}} neturi vaizdo gebėjimų", "Model {{name}} is now {{status}}": "Modelis {{name}} dabar {{status}}", @@ -1282,6 +1307,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1315,6 +1341,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Daugiau", "More Concise": "", @@ -1333,6 +1360,7 @@ "New Automation": "", "New Button": "", "New Chat": "Naujas pokalbis", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1502,6 +1530,7 @@ "Password": "Slaptažodis", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF dokumentas (.pdf)", "PDF Extract Images (OCR)": "PDF paveikslėlių skaitymas (OCR)", @@ -1609,6 +1638,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Įrašyti balsą", "Redirecting you to Open WebUI Community": "Perkeliam Jus į OpenWebUI bendruomenę", @@ -1632,6 +1662,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Pašalinti", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1650,6 +1681,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Reranking modelis", "Reset": "Atkurti", @@ -1879,7 +1911,13 @@ "Start a new conversation": "", "Start of the channel": "Kanalo pradžia", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1992,6 +2030,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "Platus paaiškinimas", "Thought": "", @@ -2011,6 +2050,7 @@ "Title cannot be an empty string.": "Pavadinimas negali būti tuščias", "Title Generation": "", "Title Generation Prompt": "Pavadinimo generavimo užklausa", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Tam, kad prieiti prie galimų parsisiųsti modelių", "To access the GGUF models available for downloading,": "Tam, kad prieiti prie galimų parsisiųsti GGUF,", @@ -2077,6 +2117,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "Atsemigti", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2181,6 +2222,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2188,6 +2230,7 @@ "What is shared:": "", "What's New in": "Kas naujo", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/lv-LV/translation.json b/src/lib/i18n/locales/lv-LV/translation.json index 648f032641..09ae34c6a3 100644 --- a/src/lib/i18n/locales/lv-LV/translation.json +++ b/src/lib/i18n/locales/lv-LV/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "{{user}} tērzēšanas", "{{webUIName}} Backend Required": "Nepieciešama {{webUIName}} aizmugursistēma", "*Prompt node ID(s) are required for image generation": "*Attēla ģenerēšanai nepieciešami uzvednes mezgla ID", + "1 hour before": "", "1 Source": "1 avots", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Sadarbības kanāls, kurā cilvēki pievienojas kā dalībnieki", "A discussion channel where access is controlled by groups and permissions": "Diskusiju kanāls, kur piekļuvi kontrolē grupas un atļaujas", "A new version (v{{LATEST_VERSION}}) is now available.": "Ir pieejama jauna versija (v{{LATEST_VERSION}}).", @@ -48,6 +53,7 @@ "Access Control": "Piekļuves kontrole", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Pieejams visiem lietotājiem", "Account": "Konts", "Account Activation Pending": "Gaida konta aktivizēšanu", @@ -73,9 +79,11 @@ "Add content here": "Pievienojiet saturu šeit", "Add Custom Parameter": "Pievienot pielāgotu parametru", "Add Custom Prompt": "Pievienot pielāgotu uzvedni", + "Add description": "", "Add Details": "Pievienot detaļas", "Add Files": "Pievienot failus", "Add Image": "", + "Add location": "", "Add Member": "Pievienot dalībnieku", "Add Members": "Pievienot dalībniekus", "Add Memory": "Pievienot atmiņu", @@ -111,6 +119,7 @@ "AI": "MI", "All": "Visi", "All chats have been unarchived.": "Visas tērzēšanas ir atarhivētas.", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Visi modeļi veiksmīgi dzēsti", @@ -199,6 +208,7 @@ "Ask a question": "Uzdot jautājumu", "Assistant": "Asistents", "Async Embedding Processing": "Asinhronā iegulšanas apstrāde", + "At time of event": "", "Attach File From Knowledge": "Pievienot failu no zināšanām", "Attach Files": "", "Attach Knowledge": "Pievienot zināšanau bāzi", @@ -273,6 +283,8 @@ "Bypass Web Loader": "Apiet tīmekļa ielādētāju", "Cache Base Model List": "Kešot bāzes modeļu sarakstu", "Calendar": "Kalendārs", + "Calendar deleted": "", + "Calendars": "", "Call": "Zvans", "Call feature is not supported when using Web STT engine": "Zvana funkcija nav atbalstīta, izmantojot Web STT dzinēju", "Camera": "Kamera", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Savienojieties ar saviem OpenAPI saderīgajiem ārējo rīku serveriem.", "Connected ({{type}})": "", "Connection failed": "Savienojums neizdevās", + "Connection lost. Reconnecting...": "", "Connection successful": "Savienojums veiksmīgs", "Connection Type": "Savienojuma tips", "Connections": "Savienojumi", @@ -440,6 +453,7 @@ "Copy Last Response": "Kopēt pēdējo atbildi", "Copy link": "Kopēt saiti", "Copy Link": "Kopēt saiti", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Kopēt starpliktuvē", @@ -520,8 +534,11 @@ "Delete All Chats": "Dzēst visas tērzēšanas", "Delete all contents inside this folder": "Dzēst visu saturu šajā mapē", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Dzēst tērzēšanu", "Delete chat?": "Dzēst tērzēšanu?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Dzēst mapi?", "Delete function?": "Dzēst funkciju?", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Kļūda: Modelis ar ID '{{modelId}}' jau eksistē. Lūdzu, izvēlieties citu ID, lai turpinātu.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Kļūda: Modeļa ID nevar būt tukšs. Lūdzu, ievadiet derīgu ID, lai turpinātu.", "Evaluations": "Novērtējumi", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API atslēga", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Piemērs: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Piemērs: ALL", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Neizdevās nokopēt saiti", "Failed to create API Key.": "Neizdevās izveidot API atslēgu.", + "Failed to delete calendar": "", "Failed to delete note": "Neizdevās dzēst piezīmi", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Neizdevās ekstrahēt saturu no faila: {{error}}", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Ierobežot vienlaicīgos meklēšanas vaicājumus. 0 = neierobežots (noklusējums). Iestatiet 1 secīgai izpildei (ieteicams API ar stingriem ātruma ierobežojumiem, piemēram, Brave bezmaksas līmenim).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "Saraksts", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Klausās...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1230,7 @@ "local": "lokāls", "Local": "Lokāls", "Local Task Model": "Lokālais uzdevumu modelis", + "Location": "", "Location access not allowed": "Atrašanās vietas piekļuve nav atļauta", "Lost": "Zaudēts", "Low": "Zems", @@ -1274,6 +1298,7 @@ "Model": "Modelis", "Model '{{modelName}}' has been successfully downloaded.": "Modelis '{{modelName}}' ir veiksmīgi lejupielādēts.", "Model '{{modelTag}}' is already in queue for downloading.": "Modelis '{{modelTag}}' jau ir lejupielādes rindā.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Modelis {{modelName}} neatbalsta redzi", "Model {{name}} is now {{status}}": "Modelis {{name}} tagad ir {{status}}", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "Modelis {{name}} tagad ir redzams", "Model accepts file inputs": "Modelis pieņem failu ievades", "Model accepts image inputs": "Modelis pieņem attēlu ievades", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Modelis var izpildīt kodu un veikt aprēķinus", "Model can generate images based on text prompts": "Modelis var ģenerēt attēlus, pamatojoties uz teksta uzvednēm", "Model can search the web for information": "Modelis var meklēt informāciju tīmeklī", @@ -1314,6 +1340,7 @@ "Models Sharing": "Modeļu kopīgošana", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Search API atslēga", + "Month": "", "Monthly": "", "More": "Vairāk", "More Concise": "Kodolīgāk", @@ -1332,6 +1359,7 @@ "New Automation": "", "New Button": "Jauna poga", "New Chat": "Jauna tērzēšana", + "New Event": "", "New File": "", "New Folder": "Jauna mape", "New Function": "Jauna funkcija", @@ -1501,6 +1529,7 @@ "Password": "Parole", "Passwords do not match.": "Paroles nesakrīt.", "Paste Large Text as File": "Ielīmēt lielu tekstu kā failu", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF dokuments (.pdf)", "PDF Extract Images (OCR)": "PDF attēlu ekstrakcija (OCR)", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "Spriedumu pūles", "Reasoning Tags": "Spriedumu tagi", "Recently Used": "", + "Reconnected": "", "Record": "Ierakstīt", "Record voice": "Ierakstīt balsi", "Redirecting you to Open WebUI Community": "Novirza jūs uz Open WebUI kopienu", @@ -1631,6 +1661,7 @@ "Relevance": "Atbilstība", "Relevance Threshold": "Atbilstības slieksnis", "Remember Dismissal": "Atcerēties noraidījumu", + "Reminder": "", "Remove": "Noņemt", "Remove {{MODELID}} from list.": "Noņemt {{MODELID}} no saraksta.", "Remove action": "", @@ -1649,6 +1680,7 @@ "Reply to thread...": "Atbildēt pavedienā...", "Replying to {{NAME}}": "Atbild {{NAME}}", "required": "nepieciešams", + "Reranking Batch Size": "", "Reranking Engine": "Pārkārtošanas dzinējs", "Reranking Model": "Pārkārtošanas modelis", "Reset": "Atiestatīt", @@ -1877,7 +1909,12 @@ "Start a new conversation": "Sākt jaunu sarunu", "Start of the channel": "Kanāla sākums", "Start Tag": "Sākuma tags", + "Starting in {{count}} minutes_zero": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "Statuss", "Status cleared successfully": "Statuss veiksmīgi notīrīts", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Tas dzēsīs {{NAME}} un visu tā saturu.", "This will delete all models including custom models": "Tas dzēsīs visus modeļus, ieskaitot pielāgotos modeļus", "This will delete all models including custom models and cannot be undone.": "Tas dzēsīs visus modeļus, ieskaitot pielāgotos modeļus, un to nevar atsaukt.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Tas atiestatīs zināšanu bāzi un sinhronizēs visus failus. Vai vēlaties turpināt?", "Thorough explanation": "Pamatīgs skaidrojums", "Thought": "", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "Virsraksts nevar būt tukša virkne.", "Title Generation": "Virsraksta ģenerēšana", "Title Generation Prompt": "Virsraksta ģenerēšanas uzvedne", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Lai piekļūtu pieejamajiem modeļu nosaukumiem lejupielādei,", "To access the GGUF models available for downloading,": "Lai piekļūtu GGUF modeļiem, kas pieejami lejupielādei,", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Izlādēs {{FROM_NOW}}", "Unlock mysteries": "Atklājiet noslēpumus", "Unpin": "Atspraust", + "Unpin from Sidebar": "", "Unravel secrets": "Atšķetiniet noslēpumus", "Unshare Chat": "", "Unsupported file type.": "Neatbalstīts faila tips.", @@ -2179,6 +2219,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI veiks pieprasījumus uz \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI veiks pieprasījumus uz \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI veiks pieprasījumus uz \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Ko jūs mēģināt sasniegt?", "What are you working on?": "Pie kā jūs strādājat?", @@ -2186,6 +2227,7 @@ "What is shared:": "Kas tiek kopīgots:", "What's New in": "Kas jauns", "What's on your mind?": "Par ko jūs domājat?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Ja iespējots, modelis atbildēs uz katru tērzēšanas ziņojumu reāllaikā, ģenerējot atbildi, tiklīdz lietotājs nosūta ziņojumu. Šis režīms ir noderīgs tiešsaistes tērzēšanas lietojumprogrammām, bet var ietekmēt veiktspēju lēnākā aparatūrā.", "wherever you are": "lai kur jūs būtu", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Vai lappušot izvadi. Katra lapa tiks atdalīta ar horizontālu līniju un lapas numuru. Noklusējums ir False.", diff --git a/src/lib/i18n/locales/ms-MY/translation.json b/src/lib/i18n/locales/ms-MY/translation.json index cf1f755f08..8dd75ac052 100644 --- a/src/lib/i18n/locales/ms-MY/translation.json +++ b/src/lib/i18n/locales/ms-MY/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "Perbualan {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Backend diperlukan", "*Prompt node ID(s) are required for image generation": "*ID nod Prompt diperlukan untuk penjanaan imej", + "1 hour before": "", "1 Source": "1 Sumber", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1m_masa_lalu", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Saluran kolaborasi di mana orang ramai menyertai sebagai ahli", "A discussion channel where access is controlled by groups and permissions": "Saluran perbincangan di mana akses dikawal oleh kumpulan dan kebenaran", "A new version (v{{LATEST_VERSION}}) is now available.": "Versi baru (v{{LATEST_VERSION}}) kini tersedia.", @@ -46,6 +51,7 @@ "Access Control": "Kawalan Akses", "Access Grants": "Pemberian Akses", "Access List": "Senarai Akses", + "Access updated": "", "Accessible to all users": "Boleh diakses oleh semua pengguna", "Account": "Akaun", "Account Activation Pending": "Pengaktifan Akaun belum selesai", @@ -71,9 +77,11 @@ "Add content here": "Tambah kandungan di sini", "Add Custom Parameter": "Tambah Parameter Tersuai", "Add Custom Prompt": "Tambah Prompt Tersuai", + "Add description": "", "Add Details": "Tambah Butiran", "Add Files": "Tambah Fail", "Add Image": "Tambah Imej", + "Add location": "", "Add Member": "Tambah Ahli", "Add Members": "Tambah Ahli", "Add Memory": "Tambah Memori", @@ -109,6 +117,7 @@ "AI": "AI", "All": "Semua", "All chats have been unarchived.": "Semua sembang telah nyaharkib.", + "All day": "", "All models are now hidden": "Semua model kini tersembunyi", "All models are now visible": "Semua model kini kelihatan", "All models deleted successfully": "Semua model telah dipadamkan dengan berjaya", @@ -197,6 +206,7 @@ "Ask a question": "Tanya soalan", "Assistant": "Pembantu", "Async Embedding Processing": "Pemprosesan Embedding Tak Segerak", + "At time of event": "", "Attach File From Knowledge": "Lampirkan Fail Daripada Pengetahuan", "Attach Files": "", "Attach Knowledge": "Lampirkan Pengetahuan", @@ -271,6 +281,8 @@ "Bypass Web Loader": "Langkau Pemuat Web", "Cache Base Model List": "Senarai Model Asas Cache", "Calendar": "Kalendar", + "Calendar deleted": "", + "Calendars": "", "Call": "Hubungi", "Call feature is not supported when using Web STT engine": "Ciri panggilan tidak disokong apabila menggunakan enjin Web STT", "Camera": "Kamera", @@ -407,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Sambung ke pelayan alat luaran yang serasi dengan OpenAPI anda sendiri.", "Connected ({{type}})": "", "Connection failed": "Sambungan gagal", + "Connection lost. Reconnecting...": "", "Connection successful": "Sambungan berjaya", "Connection Type": "Jenis Sambungan", "Connections": "Sambungan", @@ -438,6 +451,7 @@ "Copy Last Response": "Salin Respons Terakhir", "Copy link": "Salin Pautan", "Copy Link": "Salin Pautan", + "Copy Path": "", "Copy Prompt": "Salin Prompt", "Copy Share Link": "Salin Pautan Kongsian", "Copy to clipboard": "Salin ke Papan Klip", @@ -518,8 +532,11 @@ "Delete All Chats": "Padam Semua Perbualan", "Delete all contents inside this folder": "Padam semua kandungan dalam folder ini", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Padam Perbualan", "Delete chat?": "Padam perbualan?", + "Delete Event": "", "Delete File": "Padam Fail", "Delete folder?": "Padam folder?", "Delete function?": "Padam fungsi?", @@ -826,6 +843,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Ralat: Model dengan ID '{{modelId}}' sudah wujud. Sila pilih ID yang berbeza untuk meneruskan.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Ralat: ID Model tidak boleh kosong. Sila masukkan ID yang sah untuk meneruskan.", "Evaluations": "Penilaian", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Kunci API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Example: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Contoh: SEMUA", @@ -874,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "Gagal menyambung ke pelayan terminal {{URL}}", "Failed to copy link": "Gagal menyalin pautan", "Failed to create API Key.": "Gagal mencipta kekunci API", + "Failed to delete calendar": "", "Failed to delete note": "Gagal memadamkan nota", "Failed to download image": "Gagal memuat turun imej", "Failed to extract content from the file: {{error}}": "Gagal mengekstrak kandungan daripada fail: {{error}}", @@ -1195,6 +1217,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Hadkan pertanyaan carian serentak. 0 = tanpa had (lalai). Tetapkan kepada 1 untuk pelaksanaan berurutan (disyorkan untuk API dengan had kadar ketat seperti peringkat percuma Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Mengehadkan jumlah permintaan pembenaman serentak. Tetapkan kepada 0 untuk tanpa had.", "List": "Senarai", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Mendengar...", "Live": "Langsung", "Llama.cpp": "Llama.cpp", @@ -1205,6 +1228,7 @@ "local": "tempatan", "Local": "Tempatan", "Local Task Model": "Model Tugas Tempatan", + "Location": "", "Location access not allowed": "Akses lokasi tidak dibenarkan", "Lost": "Hilang", "Low": "Rendah", @@ -1272,6 +1296,7 @@ "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "Model '{{ modelName }}' telah berjaya dimuat turun.", "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{ modelTag }}' sudah dalam baris gilir untuk dimuat turun.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Model {{ modelName }} tidak mempunyai keupayaan penglihatan", "Model {{name}} is now {{status}}": "Model {{name}} kini {{status}}", @@ -1279,6 +1304,7 @@ "Model {{name}} is now visible": "Model {{name}} kini dapat dilihat", "Model accepts file inputs": "Model menerima input fail", "Model accepts image inputs": "Model menerima input imej", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Model dapat melaksanakan kod dan melakukan pengiraan", "Model can generate images based on text prompts": "Model dapat menjana imej berdasarkan gesaran teks", "Model can search the web for information": "Model boleh mencari web untuk maklumat", @@ -1312,6 +1338,7 @@ "Models Sharing": "Perkongsian Model", "Mojeek": "Mojeek", "Mojeek Search API Key": "Kunci API Pencarian Mojeek", + "Month": "", "Monthly": "", "More": "Lagi", "More Concise": "Lebih Ringkas", @@ -1330,6 +1357,7 @@ "New Automation": "", "New Button": "Butang Baru", "New Chat": "Perbualan Baru", + "New Event": "", "New File": "Fail Baru", "New Folder": "Folder Baru", "New Function": "Fungsi Baru", @@ -1499,6 +1527,7 @@ "Password": "Kata Laluan", "Passwords do not match.": "Kata laluan tidak sepadan.", "Paste Large Text as File": "Tampal Teks Besar sebagai Fail", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Dokumen PDF (.pdf)", "PDF Extract Images (OCR)": "Imej Ekstrak PDF (OCR)", @@ -1606,6 +1635,7 @@ "Reasoning Effort": "Usaha Penaakulan", "Reasoning Tags": "Tag Penaakulan", "Recently Used": "", + "Reconnected": "", "Record": "Rakaman", "Record voice": "Rakam suara", "Redirecting you to Open WebUI Community": "Membawa anda ke Komuniti OpenWebUI", @@ -1629,6 +1659,7 @@ "Relevance": "Perkaitan", "Relevance Threshold": "Ambang Perkaitan", "Remember Dismissal": "Ingat Penutupan", + "Reminder": "", "Remove": "Hapuskan", "Remove {{MODELID}} from list.": "Keluarkan {{MODELID}} daripada senarai.", "Remove action": "Keluarkan tindakan", @@ -1647,6 +1678,7 @@ "Reply to thread...": "Balas ke benang...", "Replying to {{NAME}}": "Membalas kepada {{NAME}}", "required": "diperlukan", + "Reranking Batch Size": "", "Reranking Engine": "Enjin Penyusunan Semula", "Reranking Model": "Model 'Reranking'", "Reset": "Tetapkan Semula", @@ -1873,7 +1905,10 @@ "Start a new conversation": "Mulai perbualan baru", "Start of the channel": "Permulaan saluran", "Start Tag": "Tag Permulaan", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Kernel sedang dimulakan...", + "Starting now": "", "State": "", "Status": "Status", "Status cleared successfully": "Status telah dihapus dengan berjaya", @@ -1986,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "Ini akan memadam {{NAME}} dan semua kandungannya.", "This will delete all models including custom models": "Ini akan memadam semua model termasuk model tersuai", "This will delete all models including custom models and cannot be undone.": "Ini akan memadam semua model termasuk model tersuai dan tidak boleh dibuat asal.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Ini akan menetapkan semula pangkalan pengetahuan dan menyegerakkan semua fail. Adakah anda ingin meneruskan?", "Thorough explanation": "Penjelasan menyeluruh", "Thought": "", @@ -2005,6 +2041,7 @@ "Title cannot be an empty string.": "Tajuk tidak boleh menjadi rentetan kosong", "Title Generation": "Penjanaan Tajuk", "Title Generation Prompt": "Arahan Penjanaan Tajuk", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Untuk mengakses nama model yang tersedia untuk dimuat turun,", "To access the GGUF models available for downloading,": "Untuk mengakses model GGUF yang tersedia untuk dimuat turun,", @@ -2071,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "Membuang {{FROM_NOW}}", "Unlock mysteries": "Buka Misteri", "Unpin": "Nyahsematkan", + "Unpin from Sidebar": "", "Unravel secrets": "Ungkap Rahsia", "Unshare Chat": "Batalkan Perkongsian Sembang", "Unsupported file type.": "Jenis fail tidak disokong.", @@ -2175,6 +2213,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI akan membuat permintaan ke \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI akan membuat permintaan ke \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI akan membuat permintaan ke \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Apa yang ingin anda capai?", "What are you working on?": "Apa yang sedang anda kerjakan?", @@ -2182,6 +2221,7 @@ "What is shared:": "Apa yang dikongsi:", "What's New in": "Apakah yang terbaru dalam", "What's on your mind?": "Apa yang terlintas di fikiran anda?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Apabila didayakan, model akan bertindak balas kepada setiap mesej sembang secara masa nyata, menjana respons sebaik sahaja pengguna menghantar mesej. Mod ini berguna untuk aplikasi sembang langsung, tetapi mungkin menjejaskan prestasi pada perkakasan yang lebih perlahan.", "wherever you are": "di mana pun anda berada", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Sama ada untuk memisahkan output mengikut halaman. Setiap halaman akan dipisahkan oleh garis mendatar dan nombor halaman. Lalai kepada False.", diff --git a/src/lib/i18n/locales/nb-NO/translation.json b/src/lib/i18n/locales/nb-NO/translation.json index 0fdd082794..7f45c82157 100644 --- a/src/lib/i18n/locales/nb-NO/translation.json +++ b/src/lib/i18n/locales/nb-NO/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} sine samtaler", "{{webUIName}} Backend Required": "Backend til {{webUIName}} kreves", "*Prompt node ID(s) are required for image generation": "Node-ID-er for ledetekst kreves for generering av bilder", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "En ny versjon (v{{LATEST_VERSION}}) er nå tilgjengelig.", @@ -47,6 +52,7 @@ "Access Control": "Tilgangskontroll", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Tilgjengelig for alle brukere", "Account": "Konto", "Account Activation Pending": "Venter på kontoaktivering", @@ -72,9 +78,11 @@ "Add content here": "Legg til innhold her", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Legg til filer", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Legg til minne", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Alle modeller er slettet", @@ -198,6 +207,7 @@ "Ask a question": "Still et spørsmål", "Assistant": "Assistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Kalender", + "Calendar deleted": "", + "Calendars": "", "Call": "Ring", "Call feature is not supported when using Web STT engine": "Ringefunksjonen støttes ikke når du bruker Web STT-motoren", "Camera": "Kamera", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Tilkoblinger", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Kopier lenke", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Kopier til utklippstavle", @@ -519,8 +533,11 @@ "Delete All Chats": "Slett alle chatter", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Slett chat", "Delete chat?": "Slette chat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Slette mappe?", "Delete function?": "Slette funksjon?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Vurderinger", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "API-nøkkel for Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Eksempel: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Eksempel: ALL", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Kan ikke opprette en API-nøkkel.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Lytter ...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "", "Local": "Lokal", "Local Task Model": "", + "Location": "", "Location access not allowed": "Tilgang til lokasjon er ikke tillatt", "Lost": "Tapt", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "Modell", "Model '{{modelName}}' has been successfully downloaded.": "Modellen {{modelName}} er lastet ned.", "Model '{{modelTag}}' is already in queue for downloading.": "Modellen {{modelTag}} er allerede i nedlastingskøen.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Modellen {{modelName}} er ikke egnet til visuelle data", "Model {{name}} is now {{status}}": "Modellen {{name}} er nå {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "Modellen godtar bildeinndata", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "API-nøekkel for Mojeek Search", + "Month": "", "Monthly": "", "More": "Mer", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "Ny chat", + "New Event": "", "New File": "", "New Folder": "Ny mappe", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "Passord", "Passwords do not match.": "", "Paste Large Text as File": "Lim inn mye tekst som fil", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF-dokument (.pdf)", "PDF Extract Images (OCR)": "Uthenting av PDF-bilder (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Resonneringsinnsats", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Ta opp tale", "Redirecting you to Open WebUI Community": "Omdirigerer deg til OpenWebUI-fellesskapet", @@ -1630,6 +1660,7 @@ "Relevance": "Relevans", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Fjern", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Omrangeringsmodell", "Reset": "Tilbakestill", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Starten av kanalen", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Dette sletter {{NAME}} og alt innholdet.", "This will delete all models including custom models": "Dette sletter alle modeller, inkludert tilpassede modeller", "This will delete all models including custom models and cannot be undone.": "Dette sletter alle modeller, inkludert tilpassede modeller, og kan ikke angres.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Dette tilbakestiller kunnskapsbasen og synkroniserer alle filer. Vil du fortsette?", "Thorough explanation": "Grundig forklaring", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Tittel kan ikke være en tom streng.", "Title Generation": "Genering av tittel", "Title Generation Prompt": "Ledetekst for tittelgenerering", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Hvis du vil ha tilgang til modellnavn tilgjengelige for nedlasting,", "To access the GGUF models available for downloading,": "Hvis du vil ha tilgang til GGUF-modellene tilgjengelige for nedlasting,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Lås opp mysterier", "Unpin": "Løsne", + "Unpin from Sidebar": "", "Unravel secrets": "Avslør hemmeligheter", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI vil rette forespørsler til \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI vil rette forespørsler til \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Hva prøver du å oppnå?", "What are you working on?": "Hva jobber du på nå?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "Hva er nytt i", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Hvis denne modusen er aktivert, svarer modellen på alle chattemeldinger i sanntid, og genererer et svar så snart brukeren sender en melding. Denne modusen er nyttig for live chat-applikasjoner, men kan påvirke ytelsen på tregere maskinvare.", "wherever you are": "uansett hvor du er", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/nl-NL/translation.json b/src/lib/i18n/locales/nl-NL/translation.json index f54b0190b3..4651d33fc5 100644 --- a/src/lib/i18n/locales/nl-NL/translation.json +++ b/src/lib/i18n/locales/nl-NL/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}'s chats", "{{webUIName}} Backend Required": "{{webUIName}} Backend verplicht", "*Prompt node ID(s) are required for image generation": "*Prompt node ID('s) zijn vereist voor het genereren van afbeeldingen", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Een nieuwe versie (v{{LATEST_VERSION}}) is nu beschikbaar", @@ -47,6 +52,7 @@ "Access Control": "Toegangsbeheer", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Toegankelijk voor alle gebruikers", "Account": "Account", "Account Activation Pending": "Accountactivatie in afwachting", @@ -72,9 +78,11 @@ "Add content here": "Voeg hier content toe", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Voeg bestanden toe", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Voeg geheugen toe", @@ -110,6 +118,7 @@ "AI": "", "All": "Alle", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Alle modellen zijn succesvol verwijderd", @@ -198,6 +207,7 @@ "Ask a question": "Stel een vraag", "Assistant": "Assistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Agenda", + "Calendar deleted": "", + "Calendars": "", "Call": "Oproep", "Call feature is not supported when using Web STT engine": "Belfunctie wordt niet ondersteund bij gebruik van de Web STT engine", "Camera": "Camera", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Verbind met je eigen OpenAPI-compatibele externe gereedschapservers", "Connected ({{type}})": "", "Connection failed": "Connectie mislukt", + "Connection lost. Reconnecting...": "", "Connection successful": "Connectie succesvol", "Connection Type": "Connectie type", "Connections": "Verbindingen", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "Kopiëer link", "Copy Link": "Kopieer link", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Kopieer naar klembord", @@ -519,8 +533,11 @@ "Delete All Chats": "Verwijder alle chats", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Verwijder chat", "Delete chat?": "Verwijder chat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Verwijder map?", "Delete function?": "Verwijder functie?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Beoordelingen", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API-sleutel", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Voorbeeld: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Voorbeeld: ALL", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Kan API Key niet aanmaken.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Aan het luisteren...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "", "Local": "Lokaal", "Local Task Model": "", + "Location": "", "Location access not allowed": "Locatietoegang niet toegestaan", "Lost": "Verloren", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "Model '{{modelName}}' is succesvol gedownload.", "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' staat al in de wachtrij voor downloaden.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Model {{modelName}} is niet geschikt voor visie", "Model {{name}} is now {{status}}": "Model {{name}} is nu {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "Model {{naam}} is nu zichtbaar", "Model accepts file inputs": "", "Model accepts image inputs": "Model accepteerd afbeeldingsinvoer", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API-sleutel", + "Month": "", "Monthly": "", "More": "Meer", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "Nieuwe Chat", + "New Event": "", "New File": "", "New Folder": "Nieuwe map", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "Wachtwoord", "Passwords do not match.": "", "Paste Large Text as File": "Plak grote tekst als bestand", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF document (.pdf)", "PDF Extract Images (OCR)": "PDF extraheer afbeeldingen (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Redeneerinspanning", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Neem stem op", "Redirecting you to Open WebUI Community": "Je wordt doorgestuurd naar OpenWebUI Community", @@ -1630,6 +1660,7 @@ "Relevance": "Relevantie", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Verwijderen", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Reranking Model", "Reset": "Herstellen", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Begin van het kanaal", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Dit zal {{NAME}} verwijderen en al zijn inhoud.", "This will delete all models including custom models": "Dit zal alle modellen, ook aangepaste modellen, verwijderen", "This will delete all models including custom models and cannot be undone.": "Dit zal alle modellen, ook aangepaste modellen, verwijderen en kan niet ongedaan worden gemaakt", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Dit zal de kennisdatabase resetten en alle bestanden synchroniseren. Wilt u doorgaan?", "Thorough explanation": "Grondige uitleg", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Titel kan niet leeg zijn.", "Title Generation": "Titelgeneratie", "Title Generation Prompt": "Titel Generatie Prompt", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Om de beschikbare modelnamen voor downloaden te openen,", "To access the GGUF models available for downloading,": "Om toegang te krijgen tot de GGUF-modellen die beschikbaar zijn voor downloaden,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Ontsleutel mysteries", "Unpin": "Losmaken", + "Unpin from Sidebar": "", "Unravel secrets": "Ontrafel geheimen", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI zal verzoeken doen aan \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI zal verzoeken doen aan \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Wat probeer je te bereiken?", "What are you working on?": "Waar werk je aan?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "Wat is nieuw in", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Als dit is ingeschakeld, reageert het model op elk chatbericht in real-time, waarbij een reactie wordt gegenereerd zodra de gebruiker een bericht stuurt. Deze modus is handig voor live chat-toepassingen, maar kan de prestaties op langzamere hardware beïnvloeden.", "wherever you are": "waar je ook bent", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/pa-IN/translation.json b/src/lib/i18n/locales/pa-IN/translation.json index 4e43ac1ff3..d29adc4b55 100644 --- a/src/lib/i18n/locales/pa-IN/translation.json +++ b/src/lib/i18n/locales/pa-IN/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} ਦੀਆਂ ਗੱਲਾਂ", "{{webUIName}} Backend Required": "{{webUIName}} ਬੈਕਐਂਡ ਲੋੜੀਂਦਾ ਹੈ", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -47,6 +52,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "ਖਾਤਾ", "Account Activation Pending": "", @@ -72,9 +78,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "ਫਾਈਲਾਂ ਸ਼ਾਮਲ ਕਰੋ", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "ਮਿਹਾਨ ਸ਼ਾਮਲ ਕਰੋ", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -198,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "ਕਨੈਕਸ਼ਨ", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "ਲਿੰਕ ਕਾਪੀ ਕਰੋ", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -519,8 +533,11 @@ "Delete All Chats": "ਸਾਰੀਆਂ ਚੈਟਾਂ ਨੂੰ ਮਿਟਾਓ", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "ਗੱਲਬਾਤ ਮਿਟਾਓ", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "API ਕੁੰਜੀ ਬਣਾਉਣ ਵਿੱਚ ਅਸਫਲ।", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1206,6 +1229,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "", "Model '{{modelName}}' has been successfully downloaded.": "ਮਾਡਲ '{{modelName}}' ਸਫਲਤਾਪੂਰਵਕ ਡਾਊਨਲੋਡ ਕੀਤਾ ਗਿਆ ਹੈ।", "Model '{{modelTag}}' is already in queue for downloading.": "ਮਾਡਲ '{{modelTag}}' ਪਹਿਲਾਂ ਹੀ ਡਾਊਨਲੋਡ ਲਈ ਕਤਾਰ ਵਿੱਚ ਹੈ।", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "ਮਾਡਲ {{modelName}} ਦ੍ਰਿਸ਼ਟੀ ਸਮਰੱਥ ਨਹੀਂ ਹੈ", "Model {{name}} is now {{status}}": "ਮਾਡਲ {{name}} ਹੁਣ {{status}} ਹੈ", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "ਹੋਰ", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "ਨਵੀਂ ਗੱਲਬਾਤ", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "ਪਾਸਵਰਡ", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF ਡਾਕੂਮੈਂਟ (.pdf)", "PDF Extract Images (OCR)": "PDF ਚਿੱਤਰ ਕੱਢੋ (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "ਆਵਾਜ਼ ਰਿਕਾਰਡ ਕਰੋ", "Redirecting you to Open WebUI Community": "ਤੁਹਾਨੂੰ ਓਪਨਵੈਬਯੂਆਈ ਕਮਿਊਨਿਟੀ ਵੱਲ ਰੀਡਾਇਰੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ", @@ -1630,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "ਹਟਾਓ", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "ਮਾਡਲ ਮੁੜ ਰੈਂਕਿੰਗ", "Reset": "", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "ਚੈਨਲ ਦੀ ਸ਼ੁਰੂਆਤ", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "ਵਿਸਥਾਰ ਨਾਲ ਵਿਆਖਿਆ", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "ਸਿਰਲੇਖ ਖਾਲੀ ਸਤਰ ਨਹੀਂ ਹੋ ਸਕਦਾ।", "Title Generation": "", "Title Generation Prompt": "ਸਿਰਲੇਖ ਜਨਰੇਸ਼ਨ ਪ੍ਰੰਪਟ", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "ਡਾਊਨਲੋਡ ਕਰਨ ਲਈ ਉਪਲਬਧ ਮਾਡਲ ਨਾਮਾਂ ਤੱਕ ਪਹੁੰਚਣ ਲਈ,", "To access the GGUF models available for downloading,": "ਡਾਊਨਲੋਡ ਕਰਨ ਲਈ ਉਪਲਬਧ GGUF ਮਾਡਲਾਂ ਤੱਕ ਪਹੁੰਚਣ ਲਈ,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "ਨਵਾਂ ਕੀ ਹੈ", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/pl-PL/translation.json b/src/lib/i18n/locales/pl-PL/translation.json index c41577a730..7143c47bc7 100644 --- a/src/lib/i18n/locales/pl-PL/translation.json +++ b/src/lib/i18n/locales/pl-PL/translation.json @@ -35,8 +35,13 @@ "{{user}}'s Chats": "Czaty użytkownika {{user}}", "{{webUIName}} Backend Required": "Wymagany backend {{webUIName}}", "*Prompt node ID(s) are required for image generation": "*Do generowania obrazów wymagane jest ID węzła promptu", + "1 hour before": "", "1 Source": "1 źródło", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Kanał współpracy, do którego użytkownicy dołączają jako członkowie", "A discussion channel where access is controlled by groups and permissions": "Kanał dyskusyjny, do którego dostęp jest kontrolowany przez grupy i uprawnienia", "A new version (v{{LATEST_VERSION}}) is now available.": "Dostępna jest nowa wersja (v{{LATEST_VERSION}}).", @@ -49,6 +54,7 @@ "Access Control": "Kontrola dostępu", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Dostępny dla wszystkich użytkowników", "Account": "Konto", "Account Activation Pending": "Aktywacja konta w toku", @@ -74,9 +80,11 @@ "Add content here": "Dodaj tutaj treść", "Add Custom Parameter": "Dodaj parametr niestandardowy", "Add Custom Prompt": "Dodaj niestandardowy prompt", + "Add description": "", "Add Details": "Dodaj szczegóły", "Add Files": "Dodaj pliki", "Add Image": "", + "Add location": "", "Add Member": "Dodaj członka", "Add Members": "Dodaj członków", "Add Memory": "Dodaj wpis do pamięci", @@ -112,6 +120,7 @@ "AI": "AI", "All": "Wszystkie", "All chats have been unarchived.": "Wszystkie czaty zostały przywrócone.", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Wszystkie modele zostały pomyślnie usunięte.", @@ -200,6 +209,7 @@ "Ask a question": "Zadaj pytanie", "Assistant": "Asystent", "Async Embedding Processing": "Asynchroniczne przetwarzanie embeddingów", + "At time of event": "", "Attach File From Knowledge": "Dołącz plik z bazy wiedzy", "Attach Files": "", "Attach Knowledge": "Dołącz bazę wiedzy", @@ -274,6 +284,8 @@ "Bypass Web Loader": "Pomiń Web Loader", "Cache Base Model List": "Cachuj listę modeli bazowych", "Calendar": "Kalendarz", + "Calendar deleted": "", + "Calendars": "", "Call": "Rozmowa", "Call feature is not supported when using Web STT engine": "Funkcja rozmowy nie jest obsługiwana przy użyciu przeglądarkowego silnika STT", "Camera": "Kamera", @@ -410,6 +422,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Połącz z własnymi serwerami narzędzi zgodnymi z OpenAPI.", "Connected ({{type}})": "", "Connection failed": "Połączenie nieudane", + "Connection lost. Reconnecting...": "", "Connection successful": "Połączenie udane", "Connection Type": "Typ połączenia", "Connections": "Połączenia", @@ -441,6 +454,7 @@ "Copy Last Response": "Kopiuj ostatnią odpowiedź", "Copy link": "Kopiuj link", "Copy Link": "Kopiuj link", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Kopiuj do schowka", @@ -521,8 +535,11 @@ "Delete All Chats": "Usuń wszystkie czaty", "Delete all contents inside this folder": "Usuń całą zawartość tego folderu", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Usuń czat", "Delete chat?": "Usunąć czat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Usunąć folder?", "Delete function?": "Usunąć funkcję?", @@ -829,6 +846,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Błąd: Model o ID '{{modelId}}' już istnieje. Wybierz inne ID.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Błąd: ID modelu nie może być puste. Wprowadź poprawne ID.", "Evaluations": "Ewaluacje", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Klucz API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Przykład: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Przykład: ALL", @@ -877,6 +898,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Nie udało się skopiować linku", "Failed to create API Key.": "Nie udało się utworzyć klucza API.", + "Failed to delete calendar": "", "Failed to delete note": "Nie udało się usunąć notatki", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Nie udało się wyodrębnić treści z pliku: {{error}}", @@ -1198,6 +1220,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limit jednoczesnych zapytań. 0 = brak (domyślnie). Ustaw 1 dla sekwencyjnego wykonywania (zalecane dla darmowych API np. Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "Lista", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Słucham...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1231,7 @@ "local": "lokalny", "Local": "Lokalny", "Local Task Model": "Lokalny Model Zadaniowy", + "Location": "", "Location access not allowed": "Brak dostępu do lokalizacji", "Lost": "Przegrano", "Low": "Niski", @@ -1275,6 +1299,7 @@ "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "Model '{{modelName}}' został pomyślnie pobrany.", "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' jest już w kolejce pobierania.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Model {{modelName}} nie obsługuje widzenia (Vision)", "Model {{name}} is now {{status}}": "Model {{name}} jest teraz {{status}}", @@ -1282,6 +1307,7 @@ "Model {{name}} is now visible": "Model {{name}} jest teraz widoczny", "Model accepts file inputs": "Model akceptuje pliki", "Model accepts image inputs": "Model akceptuje obrazy", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Model może wykonywać kod i obliczenia", "Model can generate images based on text prompts": "Model może generować obrazy z tekstu", "Model can search the web for information": "Model może szukać informacji w sieci", @@ -1315,6 +1341,7 @@ "Models Sharing": "Udostępnianie modeli", "Mojeek": "Mojeek", "Mojeek Search API Key": "Klucz API Mojeek Search", + "Month": "", "Monthly": "", "More": "Więcej", "More Concise": "Bardziej zwięzły", @@ -1333,6 +1360,7 @@ "New Automation": "", "New Button": "Nowy przycisk", "New Chat": "Nowy czat", + "New Event": "", "New File": "", "New Folder": "Nowy folder", "New Function": "Nowa funkcja", @@ -1502,6 +1530,7 @@ "Password": "Hasło", "Passwords do not match.": "Hasła nie pasują do siebie.", "Paste Large Text as File": "Wklej duży tekst jako plik", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Dokument PDF (.pdf)", "PDF Extract Images (OCR)": "Wyodrębnij obrazy z PDF (OCR)", @@ -1609,6 +1638,7 @@ "Reasoning Effort": "Reasoning Effort", "Reasoning Tags": "Reasoning Tags", "Recently Used": "", + "Reconnected": "", "Record": "Nagraj", "Record voice": "Nagraj głos", "Redirecting you to Open WebUI Community": "Przekierowanie do społeczności Open WebUI", @@ -1632,6 +1662,7 @@ "Relevance": "Trafność", "Relevance Threshold": "Próg trafności", "Remember Dismissal": "Zapamiętaj odrzucenie", + "Reminder": "", "Remove": "Usuń", "Remove {{MODELID}} from list.": "Usuń {{MODELID}} z listy.", "Remove action": "", @@ -1650,6 +1681,7 @@ "Reply to thread...": "Odpowiedz w wątku...", "Replying to {{NAME}}": "Odpowiedź do {{NAME}}", "required": "wymagane", + "Reranking Batch Size": "", "Reranking Engine": "Silnik Rerankingu", "Reranking Model": "Reranking Model", "Reset": "Resetuj", @@ -1879,7 +1911,13 @@ "Start a new conversation": "Rozpocznij nową rozmowę", "Start of the channel": "Początek kanału", "Start Tag": "Tag startowy", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "Status", "Status cleared successfully": "Status wyczyszczony pomyślnie", @@ -1992,6 +2030,7 @@ "This will delete {{NAME}} and all its contents.": "To usunie {{NAME}} i całą zawartość.", "This will delete all models including custom models": "To usunie wszystkie modele (w tym własne).", "This will delete all models including custom models and cannot be undone.": "To usunie wszystkie modele i jest nieodwracalne.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "To zresetuje bazę wiedzy i zsynchronizuje pliki. Kontynuować?", "Thorough explanation": "Dokładne wyjaśnienie", "Thought": "", @@ -2011,6 +2050,7 @@ "Title cannot be an empty string.": "Tytuł nie może być pusty.", "Title Generation": "Generowanie tytułu", "Title Generation Prompt": "Prompt generowania tytułu", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Aby zobaczyć nazwy modeli do pobrania,", "To access the GGUF models available for downloading,": "Aby zobaczyć modele GGUF do pobrania,", @@ -2077,6 +2117,7 @@ "Unloads {{FROM_NOW}}": "Odładowuje za {{FROM_NOW}}", "Unlock mysteries": "Odkrywaj tajemnice", "Unpin": "Odepnij", + "Unpin from Sidebar": "", "Unravel secrets": "Rozwiązuj zagadki", "Unshare Chat": "", "Unsupported file type.": "Nieobsługiwany typ pliku.", @@ -2181,6 +2222,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI będzie wysyłać żądania do \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI będzie wysyłać żądania do \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI będzie wysyłać żądania do \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Co chcesz osiągnąć?", "What are you working on?": "Nad czym pracujesz?", @@ -2188,6 +2230,7 @@ "What is shared:": "Co jest udostępniane:", "What's New in": "Co nowego w", "What's on your mind?": "O czym myślisz?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Gdy włączone, model odpowiada w czasie rzeczywistym. Tryb przydatny w czacie na żywo, ale może obciążać słabszy sprzęt.", "wherever you are": "gdziekolwiek jesteś", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Określa, czy wyniki mają być stronicowane. Strony są oddzielone linią i numerem. Domyślnie wyłączone.", diff --git a/src/lib/i18n/locales/pt-BR/translation.json b/src/lib/i18n/locales/pt-BR/translation.json index 2a4e99c95c..bde1024811 100644 --- a/src/lib/i18n/locales/pt-BR/translation.json +++ b/src/lib/i18n/locales/pt-BR/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Chats de {{user}}", "{{webUIName}} Backend Required": "Backend {{webUIName}} necessário", "*Prompt node ID(s) are required for image generation": "*Prompt node ID(s) são obrigatórios para gerar imagens", + "1 hour before": "", "1 Source": "1 Origem", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1m atrás", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Um canal de colaboração onde as pessoas se juntam como membros.", "A discussion channel where access is controlled by groups and permissions": "Um canal de discussão onde o acesso é controlado por grupos e permissões.", "A new version (v{{LATEST_VERSION}}) is now available.": "Uma nova versão (v{{LATEST_VERSION}}) está disponível.", @@ -48,6 +53,7 @@ "Access Control": "Controle de Acesso", "Access Grants": "Concessões de Acesso", "Access List": "Lista de acesso", + "Access updated": "Acesso atualizado", "Accessible to all users": "Acessível para todos os usuários", "Account": "Conta", "Account Activation Pending": "Ativação da Conta Pendente", @@ -73,9 +79,11 @@ "Add content here": "Adicionar conteúdo aqui", "Add Custom Parameter": "Adicionar parâmetro personalizado", "Add Custom Prompt": "Adicionar prompt personalizado", + "Add description": "", "Add Details": "Adicionar detalhes", "Add Files": "Adicionar Arquivos", "Add Image": "Adicionar imagem", + "Add location": "", "Add Member": "Adicionar membro", "Add Members": "Adicionar membros", "Add Memory": "Adicionar Memória", @@ -111,6 +119,7 @@ "AI": "IA", "All": "Tudo", "All chats have been unarchived.": "Todos os chats foram desarquivados.", + "All day": "", "All models are now hidden": "Todos os modelos estão agora ocultos", "All models are now visible": "Todos os modelos estão agora visíveis", "All models deleted successfully": "Todos os modelos foram excluídos com sucesso", @@ -199,6 +208,7 @@ "Ask a question": "Faça uma pergunta", "Assistant": "Assistente", "Async Embedding Processing": "Processamento de Embedding assíncrono", + "At time of event": "", "Attach File From Knowledge": "Anexar arquivo da base de conhecimento", "Attach Files": "Anexar arquivos", "Attach Knowledge": "Anexar Base de Conhecimento", @@ -273,6 +283,8 @@ "Bypass Web Loader": "Ignorar carregador da Web", "Cache Base Model List": "Lista de modelos base de cache", "Calendar": "Calendário", + "Calendar deleted": "", + "Calendars": "", "Call": "Chamada", "Call feature is not supported when using Web STT engine": "O recurso de chamada não é suportado ao usar o mecanismo Web STT", "Camera": "Câmera", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Conecte-se aos seus próprios servidores de ferramentas externas compatíveis com OpenAPI.", "Connected ({{type}})": "Conectado ({{type}})", "Connection failed": "Falha na conexão", + "Connection lost. Reconnecting...": "", "Connection successful": "Conexão bem-sucedida", "Connection Type": "Tipo de conexão", "Connections": "Conexões", @@ -440,6 +453,7 @@ "Copy Last Response": "Copiar última resposta", "Copy link": "Copiar link", "Copy Link": "Copiar Link", + "Copy Path": "Copiar caminho", "Copy Prompt": "Copiar prompt", "Copy Share Link": "Copiar link de compartilhamento", "Copy to clipboard": "Copiar para a área de transferência", @@ -455,7 +469,7 @@ "Create a new note": "Criar uma nova nota", "Create Account": "Criar Conta", "Create Admin Account": "Criar Conta de Administrador", - "Create and manage scheduled automations": "", + "Create and manage scheduled automations": "Criar e gerenciar automações agendadas", "Create Channel": "Criar Canal", "Create Folder": "Criar Pasta", "Create Image": "Criar imagem", @@ -481,7 +495,7 @@ "Custom Gender": "Gênero personalizado", "Custom Parameter Name": "Nome do parâmetro personalizado", "Custom Parameter Value": "Valor do parâmetro personalizado", - "Daily": "", + "Daily": "Diário", "Daily Messages": "Mensagens Diárias", "Danger Zone": "Zona de Perigo", "Dark": "Escuro", @@ -520,8 +534,11 @@ "Delete All Chats": "Excluir Todos os Chats", "Delete all contents inside this folder": "Apague todo o conteúdo desta pasta.", "Delete automation?": "Excluir automação?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Excluir Chat", "Delete chat?": "Excluir chat?", + "Delete Event": "", "Delete File": "Excluir arquivo", "Delete folder?": "Excluir pasta?", "Delete function?": "Excluir função?", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Erro: Já existe um modelo com o ID '{{modelId}}'. Selecione um ID diferente para prosseguir.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Erro: O ID do modelo não pode estar vazio. Insira um ID válido para prosseguir.", "Evaluations": "Avaliações", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Chave da API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemplo: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exemplo: ALL", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "Falha ao conectar ao servidor de terminal {{URL}}", "Failed to copy link": "Falha ao copiar o link", "Failed to create API Key.": "Falha ao criar a Chave API.", + "Failed to delete calendar": "", "Failed to delete note": "Falha ao excluir a nota", "Failed to download image": "Falha ao baixar a imagem", "Failed to extract content from the file: {{error}}": "Falha ao extrair conteúdo do arquivo: {{error}}", @@ -972,7 +994,7 @@ "Forward": "Encaminhar", "Forwards system user OAuth access token to authenticate": "Encaminha o token de acesso OAuth do usuário do sistema para autenticação", "Forwards system user session credentials to authenticate": "Encaminha as credenciais da sessão do usuário do sistema para autenticação", - "Fr_day_of_week": "", + "Fr_day_of_week": "Sex", "Full Context Mode": "Modo de contexto completo", "Function": "Função", "Function Calling": "Chamada de função", @@ -1047,7 +1069,7 @@ "History": "Histórico", "Home": "Início", "Host": "Servidor", - "Hourly": "", + "Hourly": "A cada hora", "Hourly Messages": "Mensagens por Hora", "How can I help you today?": "Como posso ajudar você hoje?", "How would you rate this response?": "Como você avalia essa resposta?", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limitar consultas de pesquisa simultâneas. 0 = ilimitado (padrão). Defina como 1 para execução sequencial (recomendado para APIs com limites de taxa rígidos, como o nível gratuito do Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limita o número de solicitações simultâneas de embedding. Defina como 0 para ilimitado.", "List": "Lista", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Escutando...", "Live": "Ao vivo", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1230,7 @@ "local": "local", "Local": "Local", "Local Task Model": "Modelo de Tarefa Local", + "Location": "", "Location access not allowed": "Acesso ao local não permitido", "Lost": "Perdeu", "Low": "Baixo", @@ -1270,10 +1294,11 @@ "Mistral OCR": "Mistral OCR", "Mistral OCR API Key required.": "Chave de API do Mistral OCR necessária.", "MistralAI": "MistralAI", - "Mo_day_of_week": "", + "Mo_day_of_week": "Seg", "Model": "Modelo", "Model '{{modelName}}' has been successfully downloaded.": "Modelo '{{modelName}}' foi baixado com sucesso.", "Model '{{modelTag}}' is already in queue for downloading.": "Modelo '{{modelTag}}' já está na fila para download.", + "Model {{modelId}} not found": "Modelo {{modelId}} não encontrado", "Model {{modelName}} deleted successfully": "Modelo {{modelName}} excluído com sucesso", "Model {{modelName}} is not vision capable": "Modelo {{modelName}} não é capaz de visão", "Model {{name}} is now {{status}}": "Modelo {{name}} está agora {{status}}", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "O modelo {{name}} agora está visível", "Model accepts file inputs": "O modelo aceita entradas de arquivo", "Model accepts image inputs": "Modelo aceita entradas de imagens", + "Model can access Open Terminal for command execution and file management": "O modelo pode acessar o Open Terminal para execução de comandos e gerenciamento de arquivos", "Model can execute code and perform calculations": "O modelo pode executar código e realizar cálculos", "Model can generate images based on text prompts": "O modelo pode gerar imagens com base em prompts de texto", "Model can search the web for information": "O modelo pode pesquisar informações na web", @@ -1314,7 +1340,8 @@ "Models Sharing": "Compartilhamento de Modelos", "Mojeek": "Mojeek", "Mojeek Search API Key": "Chave de API Mojeek Search", - "Monthly": "", + "Month": "", + "Monthly": "Mensal", "More": "Mais", "More Concise": "Mais conciso", "More options": "Mais opções", @@ -1332,6 +1359,7 @@ "New Automation": "Nova Automação", "New Button": "Novo Botão", "New Chat": "Novo Chat", + "New Event": "", "New File": "Novo Arquivo", "New Folder": "Nova Pasta", "New Function": "Nova Função", @@ -1435,7 +1463,7 @@ "Ollama Cloud API Key": "Chave da API Ollama Cloud", "Ollama Version": "Versão Ollama", "On": "Ligado", - "Once": "", + "Once": "Uma vez", "OneDrive": "OneDrive", "Only active when \"Paste Large Text as File\" setting is toggled on.": "Ativo somente quando a configuração \"Colar texto grande como arquivo\" estiver ativada.", "Only active when the chat input is in focus and an LLM is generating a response.": "Ativo somente quando o campo de entrada do chat está em foco e um LLM está gerando uma resposta.", @@ -1485,7 +1513,7 @@ "or": "ou", "Ordered List": "Lista ordenada", "Other": "Outro", - "out of": "", + "out of": "de", "Output": "Saída", "OUTPUT": "SAÍDA", "Output format": "Formato de saída", @@ -1501,6 +1529,7 @@ "Password": "Senha", "Passwords do not match.": "As senhas não coincidem.", "Paste Large Text as File": "Cole Textos Longos como Arquivo", + "Path copied": "Caminho copiado", "Paused": "Em pausa", "PDF document (.pdf)": "Documento PDF (.pdf)", "PDF Extract Images (OCR)": "Extrair Imagens do PDF (OCR)", @@ -1520,7 +1549,7 @@ "Persistent": "Persistente", "Personalization": "Personalização", "Pin": "Fixar", - "Pin to Sidebar": "", + "Pin to Sidebar": "Fixar na barra lateral", "Pinned": "Fixado", "Pinned Messages": "Mensagens fixadas", "Pinned Models": "Modelos Fixados", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "Esforço de raciocínio", "Reasoning Tags": "Tags de raciocínio", "Recently Used": "Usado recentemente", + "Reconnected": "", "Record": "Gravar", "Record voice": "Gravar voz", "Redirecting you to Open WebUI Community": "Redirecionando você para a Comunidade OpenWebUI", @@ -1631,6 +1661,7 @@ "Relevance": "Relevância", "Relevance Threshold": "Limiar de Relevância", "Remember Dismissal": "Lembrar da dispensa", + "Reminder": "", "Remove": "Remover", "Remove {{MODELID}} from list.": "Remover {{MODELID}} da lista.", "Remove action": "Remover ação", @@ -1649,6 +1680,7 @@ "Reply to thread...": "Responder ao tópico...", "Replying to {{NAME}}": "Respondendo para {{NAME}}", "required": "obrigatório", + "Reranking Batch Size": "Tamanho do lote de reclassificação", "Reranking Engine": "Motor de Reclassificação", "Reranking Model": "Modelo de Reclassificação", "Reset": "Redefinir", @@ -1682,7 +1714,7 @@ "Running": "Executando", "Running...": "Executando...", "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "Executa tarefas de incorporação simultaneamente para acelerar o processamento. Desative se os limites de taxa se tornarem um problema.", - "Sa_day_of_week": "", + "Sa_day_of_week": "Sáb", "Save": "Salvar", "Save & Create": "Salvar e Criar", "Save & Update": "Salvar e Atualizar", @@ -1877,7 +1909,12 @@ "Start a new conversation": "Iniciar uma nova conversa", "Start of the channel": "Início do canal", "Start Tag": "Tag inicial", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Iniciando kernel...", + "Starting now": "", "State": "Estado", "Status": "Status", "Status cleared successfully": "Status liberado com sucesso", @@ -1899,7 +1936,7 @@ "STT Model": "Modelo STT", "STT Settings": "Configurações STT", "Stylized PDF Export": "Exportação de PDF estilizado", - "Su_day_of_week": "", + "Su_day_of_week": "Dom", "Submit question": "Enviar pergunta", "Submit suggestion": "Enviar sugestão", "Subtitle": "Subtítulo", @@ -1945,7 +1982,7 @@ "Text Splitter": "Divisor de Texto", "Text-to-Speech": "Texto-para-Fala", "Text-to-Speech Engine": "Motor de Texto para Fala", - "Th_day_of_week": "", + "Th_day_of_week": "Qui", "Thanks for your feedback!": "Obrigado pelo seu comentário!", "The Application Account DN you bind with for search": "O DN (Distinguished Name) da Conta de Aplicação com a qual você se conecta para pesquisa.", "The base to search for users": "Base para pesquisar usuários.", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Esta ação excluirá {{NAME}} e todos seus conteúdos.", "This will delete all models including custom models": "Isto vai excluir todos os modelos, incluindo personalizados", "This will delete all models including custom models and cannot be undone.": "Isto vai excluir todos os modelos, incluindo personalizados e não pode ser desfeito.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Esta ação resetará a base de conhecimento e sincronizará todos os arquivos. Deseja continuar?", "Thorough explanation": "Explicação detalhada", "Thought": "Pensamento", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "O Título não pode ser uma string vazia.", "Title Generation": "Geração de Títulos", "Title Generation Prompt": "Prompt de Geração de Título", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Para acessar os nomes de modelos disponíveis para download,", "To access the GGUF models available for downloading,": "Para acessar os modelos GGUF disponíveis para download,", @@ -2059,7 +2098,7 @@ "TTS Model": "Modelo TTS", "TTS Settings": "Configurações TTS", "TTS Voice": "Voz TTS", - "Tu_day_of_week": "", + "Tu_day_of_week": "Ter", "Type": "Tipo", "Type here...": "Digite aqui...", "Type Hugging Face Resolve (Download) URL": "Digite o URL de download do Hugging Face", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Descarrega {{FROM_NOW}}", "Unlock mysteries": "Desvendar mistérios", "Unpin": "Desfixar", + "Unpin from Sidebar": "", "Unravel secrets": "Desvendar segredos", "Unshare Chat": "Cancelar compartilhamento do chat", "Unsupported file type.": "Tipo de arquivo não suportado.", @@ -2162,7 +2202,7 @@ "Warning: Enabling this will allow users to run scheduled prompts automatically.": "Aviso: Habilitar esta opção permitirá que os usuários executem solicitações agendadas automaticamente.", "Warning: Enabling this will allow users to upload arbitrary code on the server.": "Aviso: Habilitar isso permitirá que os usuários façam upload de código arbitrário no servidor.", "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "Aviso: a execução do Jupyter permite a execução de código arbitrário, o que representa sérios riscos de segurança. Prossiga com extremo cuidado.", - "We_day_of_week": "", + "We_day_of_week": "Qua", "Web": "Web", "Web API": "API Web", "Web Loader Engine": "Motor de carregamento da Web", @@ -2179,13 +2219,15 @@ "WebUI will make requests to \"{{url}}\"": "A WebUI fará requisições para \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "A WebUI fará requisições para \"{{url}}/api/chat\".", "WebUI will make requests to \"{{url}}/chat/completions\"": "A WebUI fará requisições para \"{{url}}/chat/completions\".", - "Weekly": "", + "Week": "", + "Weekly": "Semanal", "What are you trying to achieve?": "O que está tentando alcançar?", "What are you working on?": "No que está trabalhando?", "What is NOT shared:": "O que NÃO é compartilhado:", "What is shared:": "O que é compartilhado", "What's New in": "O que há de novo em", "What's on your mind?": "O que você tem em mente?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Quando habilitado, o modelo responderá a cada mensagem de chat em tempo real, gerando uma resposta assim que o usuário enviar uma mensagem. Este modo é útil para aplicativos de chat ao vivo, mas pode impactar o desempenho em hardware mais lento.", "wherever you are": "onde quer que você esteja.", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Se a saída deve ser paginada. Cada página será separada por uma régua horizontal e um número de página. O padrão é Falso.", diff --git a/src/lib/i18n/locales/pt-PT/translation.json b/src/lib/i18n/locales/pt-PT/translation.json index 76c97853a2..1b9c2e7e48 100644 --- a/src/lib/i18n/locales/pt-PT/translation.json +++ b/src/lib/i18n/locales/pt-PT/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Chats de {{user}}", "{{webUIName}} Backend Required": "Backend {{webUIName}} Necessário", "*Prompt node ID(s) are required for image generation": "*ID(s) do nó de prompt são necessários para a geração de imagem", + "1 hour before": "", "1 Source": "Uma Fonte", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "há 1 minuto", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Um canal de colaboração onde as pessoas entram como membros", "A discussion channel where access is controlled by groups and permissions": "Um canal de discussão onde o acesso é controlado por grupos e permissões", "A new version (v{{LATEST_VERSION}}) is now available.": "Uma nova versão (v{{LATEST_VERSION}}) está agora disponível.", @@ -48,6 +53,7 @@ "Access Control": "Controlo de Acesso", "Access Grants": "Concessões de Acesso", "Access List": "Lista de Acesso", + "Access updated": "", "Accessible to all users": "Acessível a todos os utilizadores", "Account": "Conta", "Account Activation Pending": "Ativação da Conta Pendente", @@ -73,9 +79,11 @@ "Add content here": "Adicionar conteúdo aqui", "Add Custom Parameter": "Adicionar Parâmetro Personalizado", "Add Custom Prompt": "Adicionar Prompt Personalizado", + "Add description": "", "Add Details": "Adicionar Detalhes", "Add Files": "Adicionar Ficheiros", "Add Image": "Adicionar Imagem", + "Add location": "", "Add Member": "Adicionar Membro", "Add Members": "Adicionar Membros", "Add Memory": "Adicionar memória", @@ -111,6 +119,7 @@ "AI": "IA", "All": "Todos", "All chats have been unarchived.": "Todos as conversas foram desarquivadas.", + "All day": "", "All models are now hidden": "Todos os modelos estão agora ocultos", "All models are now visible": "Todos os modelos estão agora visíveis", "All models deleted successfully": "Todos os modelos foram eliminados com sucesso", @@ -199,6 +208,7 @@ "Ask a question": "Fazer uma pergunta", "Assistant": "Assistente", "Async Embedding Processing": "Incorporação de Processamento Assíncrono", + "At time of event": "", "Attach File From Knowledge": "Anexar Ficheiro do Conhecimento", "Attach Files": "", "Attach Knowledge": "Anexar Conhecimento", @@ -273,6 +283,8 @@ "Bypass Web Loader": "Ignorar Carregador Web", "Cache Base Model List": "Cache da Lista de Modelos Base", "Calendar": "Calendário", + "Calendar deleted": "", + "Calendars": "", "Call": "Chamar", "Call feature is not supported when using Web STT engine": "A funcionalide de Chamar não é suportada quando usa um motor Web STT", "Camera": "Câmara", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Ligar ao seu próprio servidor de ferramentas externo compatível com a OpenAI.", "Connected ({{type}})": "", "Connection failed": "Ligação falhou", + "Connection lost. Reconnecting...": "", "Connection successful": "Ligação bem sucedida", "Connection Type": "Tipo de ligação", "Connections": "Ligações", @@ -440,6 +453,7 @@ "Copy Last Response": "Copiar Última Resposta", "Copy link": "Copiar link", "Copy Link": "Copiar Link", + "Copy Path": "", "Copy Prompt": "Copiar Prompt", "Copy Share Link": "Copiar Partilha de Link", "Copy to clipboard": "Copiar para a área de transferência", @@ -520,8 +534,11 @@ "Delete All Chats": "Apagar todas as conversas", "Delete all contents inside this folder": "Apagar todo o conteúdo dentro desta pasta", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Apagar Conversa", "Delete chat?": "Apagar conversa?", + "Delete Event": "", "Delete File": "Apagar ficheiro", "Delete folder?": "Apagar pasta", "Delete function?": "Apagar função", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Erro: Um modelo com o ID '{{modelId}}' já existe. Por favor, selecione um ID diferente para continuar.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Erro: O ID do modelo não pode estar vazio. Por favor insira o ID válido para continuar.", "Evaluations": "Avaliações", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Chave da API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemplo: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "Falha na ligação ao terminal de servidores {{URL}}", "Failed to copy link": "Falha ao copiar a hiperligação", "Failed to create API Key.": "Falha ao criar a Chave da API.", + "Failed to delete calendar": "", "Failed to delete note": "Falha ao apagar a nota", "Failed to download image": "Falha ao transferir a imagem", "Failed to extract content from the file: {{error}}": "Falha ao extrair conteúdo do ficheiro: {{error}}", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limitar consultas de pesquisa simultâneas. 0 = ilimitado (padrão). Defina como 1 para execução sequencial (recomendado para APIs com limites de taxa rigorosos, como o nível gratuito do Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limita o número de solicitações de incorporação simultâneas. Defina como 0 para ilimitado.", "List": "Lista", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "A ouvir...", "Live": "Ao vivo", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1230,7 @@ "local": "local", "Local": "Local", "Local Task Model": "Modelo de Tarefa Local", + "Location": "", "Location access not allowed": "Acesso à localização não permitido", "Lost": "Perdido", "Low": "Baixo", @@ -1274,6 +1298,7 @@ "Model": "Modelo", "Model '{{modelName}}' has been successfully downloaded.": "O modelo '{{modelName}}' foi descarregado com sucesso.", "Model '{{modelTag}}' is already in queue for downloading.": "O modelo '{{modelTag}}' já está na fila para descarregar.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "O modelo {{modelName}} não é capaz de visão", "Model {{name}} is now {{status}}": "Modelo {{name}} agora é {{status}}", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "Modelo {{name}} agora está visível", "Model accepts file inputs": "O modelo aceita entradas de ficheiros", "Model accepts image inputs": "O modelo aceita entradas de imagens", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "O modelo pode executar código e realizar cálculos", "Model can generate images based on text prompts": "O modelo pode gerar imagens com base em prompts de texto", "Model can search the web for information": "O modelo pode pesquisar na web por informações", @@ -1314,6 +1340,7 @@ "Models Sharing": "Partilha de Modelos", "Mojeek": "Mojeek", "Mojeek Search API Key": "Chave API de Pesquisa Mojeek", + "Month": "", "Monthly": "", "More": "Mais", "More Concise": "Mais Conciso", @@ -1332,6 +1359,7 @@ "New Automation": "", "New Button": "Novo Botão", "New Chat": "Nova Conversa", + "New Event": "", "New File": "Novo Ficheiro", "New Folder": "Nova Pasta", "New Function": "Nova Função", @@ -1501,6 +1529,7 @@ "Password": "Senha", "Passwords do not match.": "As palavras-passe não coincidem.", "Paste Large Text as File": "Colar Texto Grande como Arquivo", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Documento PDF (.pdf)", "PDF Extract Images (OCR)": "Extrair Imagens de PDF (OCR)", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "Esforço de Raciocínio", "Reasoning Tags": "Etiquetas de Raciocínio", "Recently Used": "", + "Reconnected": "", "Record": "Gravar", "Record voice": "Gravar voz", "Redirecting you to Open WebUI Community": "Redirecionando-o para a Comunidade OpenWebUI", @@ -1631,6 +1661,7 @@ "Relevance": "Relevância", "Relevance Threshold": "Limite de Relevância", "Remember Dismissal": "Lembrar Descartar", + "Reminder": "", "Remove": "Remover", "Remove {{MODELID}} from list.": "Remover {{MODELID}} da lista.", "Remove action": "Remover ação", @@ -1649,6 +1680,7 @@ "Reply to thread...": "Responder ao tópico...", "Replying to {{NAME}}": "A responder a {{NAME}}", "required": "obrigatório", + "Reranking Batch Size": "", "Reranking Engine": "Motor de Reclassificação", "Reranking Model": "Modelo de Reclassificação", "Reset": "Repor", @@ -1877,7 +1909,12 @@ "Start a new conversation": "Iniciar uma nova conversa", "Start of the channel": "Início do canal", "Start Tag": "Início da Tag", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Iniciando kernel...", + "Starting now": "", "State": "", "Status": "Estado", "Status cleared successfully": "Estado limpo com sucesso", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Isto irá excluir {{NAME}} e todo o seu conteúdo.", "This will delete all models including custom models": "Isto irá excluir todos os modelos, incluindo os modelos personalizados", "This will delete all models including custom models and cannot be undone.": "Isto irá excluir todos os modelos, incluindo os modelos personalizados, e não pode ser desfeito.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Isto irá redefinir a base de conhecimento e sincronizar todos os arquivos. Deseja continuar?", "Thorough explanation": "Explicação Minuciosa", "Thought": "", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "Título não pode ser uma string vazia.", "Title Generation": "Geração de Título", "Title Generation Prompt": "Prompt de Geração de Título", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Para aceder aos nomes de modelo disponíveis para descarregar,", "To access the GGUF models available for downloading,": "Para aceder aos modelos GGUF disponíveis para descarregar,", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Descarreva {{FROM_NOW}}", "Unlock mysteries": "Desbloquear Mistérios", "Unpin": "Desafixar", + "Unpin from Sidebar": "", "Unravel secrets": "Desvendar segredos", "Unshare Chat": "Parar partilha de conversa", "Unsupported file type.": "Tipo de ficheiro não suportado", @@ -2179,6 +2219,7 @@ "WebUI will make requests to \"{{url}}\"": "O WebUI fará solicitações para \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "O WebUI fará solicitações para \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "O WebUI fará solicitações para \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "O que você está tentando alcançar?", "What are you working on?": "Em que você está trabalhando?", @@ -2186,6 +2227,7 @@ "What is shared:": "O que é compartilhado:", "What's New in": "O que há de novo em", "What's on your mind?": "O que está A pensaR?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Quando ativado, o modelo responderá a cada mensagem do chat em tempo real, gerando uma resposta assim que o utilizador enviar uma mensagem. Este modo é útil para aplicações de chat ao vivo, mas pode impactar o desempenho em hardware mais lento.", "wherever you are": "onde quer que esteja", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Se deve paginar a saída. Cada página será separada por uma linha horizontal e número de página. Padrão é Falso.", diff --git a/src/lib/i18n/locales/ro-RO/translation.json b/src/lib/i18n/locales/ro-RO/translation.json index 83ffb71fb9..3028840716 100644 --- a/src/lib/i18n/locales/ro-RO/translation.json +++ b/src/lib/i18n/locales/ro-RO/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Conversațiile lui {{user}}", "{{webUIName}} Backend Required": "Este necesar backend-ul {{webUIName}}", "*Prompt node ID(s) are required for image generation": "*Sunt necesare ID-urile nodurilor de solicitare pentru generarea imaginii*", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "O nouă versiune (v{{LATEST_VERSION}}) este acum disponibilă.", @@ -48,6 +53,7 @@ "Access Control": "Controlul accesului", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Accesibil pentru toți utilizatorii", "Account": "Cont", "Account Activation Pending": "Activarea contului în așteptare", @@ -73,9 +79,11 @@ "Add content here": "Adăugați conținut aici", "Add Custom Parameter": "Adaugă parametru personalizat", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Adaugă fișiere", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Adaugă memorie", @@ -111,6 +119,7 @@ "AI": "", "All": "Toate", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Toate modelele au fost șterse cu succes", @@ -199,6 +208,7 @@ "Ask a question": "Pune o întrebare", "Assistant": "Asistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -273,6 +283,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "Apel", "Call feature is not supported when using Web STT engine": "Funcția de apel nu este suportată când se utilizează motorul Web STT", "Camera": "Cameră", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "Conexiune eșuată", + "Connection lost. Reconnecting...": "", "Connection successful": "Conexiune reușită", "Connection Type": "Tip conexiune", "Connections": "Conexiuni", @@ -440,6 +453,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Copiază Link", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Copiază în clipboard", @@ -520,8 +534,11 @@ "Delete All Chats": "Șterge Toate Conversațiile", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Șterge Conversația", "Delete chat?": "Șterge conversația?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Ștergeți folderul?", "Delete function?": "Șterge funcția?", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Evaluări", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Crearea cheii API a eșuat.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Ascult...", "Live": "", "Llama.cpp": "", @@ -1207,6 +1230,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Pierdut", "Low": "", @@ -1274,6 +1298,7 @@ "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "Modelul '{{modelName}}' a fost descărcat cu succes.", "Model '{{modelTag}}' is already in queue for downloading.": "Modelul '{{modelTag}}' este deja în coada de descărcare.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Modelul {{modelName}} nu are capacități de viziune", "Model {{name}} is now {{status}}": "Modelul {{name}} este acum {{status}}", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "Modelul acceptă imagini ca intrări.", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1314,6 +1340,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Mai multe", "More Concise": "", @@ -1332,6 +1359,7 @@ "New Automation": "", "New Button": "", "New Chat": "Conversație Nouă", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1501,6 +1529,7 @@ "Password": "Parolă", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Document PDF (.pdf)", "PDF Extract Images (OCR)": "Extrage Imagini PDF (OCR)", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Înregistrează vocea", "Redirecting you to Open WebUI Community": "Vă redirecționăm către Comunitatea OpenWebUI", @@ -1631,6 +1661,7 @@ "Relevance": "Relevanță", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Înlătură", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1649,6 +1680,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Model de Rearanjare", "Reset": "Resetează", @@ -1877,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "Începutul canalului", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Acest lucru va șterge {{NAME}} și toate conținuturile sale.", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Aceasta va reseta baza de cunoștințe și va sincroniza toate fișierele. Doriți să continuați?", "Thorough explanation": "Explicație detaliată", "Thought": "", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "Titlul nu poate fi un șir gol.", "Title Generation": "", "Title Generation Prompt": "Prompt de Generare a Titlului", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Pentru a accesa numele modelelor disponibile pentru descărcare,", "To access the GGUF models available for downloading,": "Pentru a accesa modelele GGUF disponibile pentru descărcare,", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "Anulează Fixarea", + "Unpin from Sidebar": "", "Unravel secrets": "Dezvăluie secretele", "Unshare Chat": "", "Unsupported file type.": "", @@ -2179,6 +2219,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2186,6 +2227,7 @@ "What is shared:": "", "What's New in": "Ce e Nou în", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/ru-RU/translation.json b/src/lib/i18n/locales/ru-RU/translation.json index 6c62e7a09d..954d8f7f4e 100644 --- a/src/lib/i18n/locales/ru-RU/translation.json +++ b/src/lib/i18n/locales/ru-RU/translation.json @@ -35,8 +35,13 @@ "{{user}}'s Chats": "Чаты {{user}}'а", "{{webUIName}} Backend Required": "Необходимо подключение к серверу {{webUIName}}", "*Prompt node ID(s) are required for image generation": "ID узлов промптов обязательны для генерации изображения", + "1 hour before": "", "1 Source": "1 Источник", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1 мин назад", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Канал для совместной работы с присоединением участников", "A discussion channel where access is controlled by groups and permissions": "Обсуждение канала, где доступ контролируется группами и разрешениями", "A new version (v{{LATEST_VERSION}}) is now available.": "Новая версия (v{{LATEST_VERSION}}) теперь доступна.", @@ -49,6 +54,7 @@ "Access Control": "Контроль доступа", "Access Grants": "Права доступа", "Access List": "Список доступов", + "Access updated": "", "Accessible to all users": "Доступно всем пользователям", "Account": "Учетная запись", "Account Activation Pending": "Ожидание активации учетной записи", @@ -74,9 +80,11 @@ "Add content here": "Добавить контент сюда", "Add Custom Parameter": "Добавить пользовательский параметр", "Add Custom Prompt": "Добавить пользовательский запрос", + "Add description": "", "Add Details": "Добавить детали", "Add Files": "Добавить файлы", "Add Image": "Добавить изображение", + "Add location": "", "Add Member": "Добавить участника", "Add Members": "Добавить участников", "Add Memory": "Добавить воспоминание", @@ -112,6 +120,7 @@ "AI": "AI", "All": "Все", "All chats have been unarchived.": "Все чаты были разархивированы.", + "All day": "", "All models are now hidden": "Все модели скрыты", "All models are now visible": "Все модели видимы", "All models deleted successfully": "Все модели успешно удалены", @@ -200,6 +209,7 @@ "Ask a question": "Задать вопрос", "Assistant": "Ассистент", "Async Embedding Processing": "Асинхронная обработка эмбеддингов", + "At time of event": "", "Attach File From Knowledge": "Прикрепить файл из знаний", "Attach Files": "", "Attach Knowledge": "Прикрепить знания", @@ -274,6 +284,8 @@ "Bypass Web Loader": "Обход веб-загрузчика", "Cache Base Model List": "Кэшировать список базовых моделей", "Calendar": "Календарь", + "Calendar deleted": "", + "Calendars": "", "Call": "Вызов", "Call feature is not supported when using Web STT engine": "Функция вызова не поддерживается при использовании Web STT (распознавание речи) движка", "Camera": "Камера", @@ -410,6 +422,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Подключитесь к вашим собственным внешним инструментальным серверам, совместимым с OpenAPI.", "Connected ({{type}})": "Подключено ({{type}})", "Connection failed": "Подключение не удалось", + "Connection lost. Reconnecting...": "", "Connection successful": "Успешное подключение", "Connection Type": "Тип подключения", "Connections": "Подключения", @@ -441,6 +454,7 @@ "Copy Last Response": "Копировать последний ответ", "Copy link": "Скопировать ссылку", "Copy Link": "Копировать ссылку", + "Copy Path": "", "Copy Prompt": "Копировать запрос", "Copy Share Link": "Копировать ссылку для обмена", "Copy to clipboard": "Скопировать в буфер обмена", @@ -521,8 +535,11 @@ "Delete All Chats": "Удалить ВСЕ Чаты", "Delete all contents inside this folder": "Удалить все содержимое внутри этой папки", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Удалить Чат", "Delete chat?": "Удалить чат?", + "Delete Event": "", "Delete File": "Удалить файл", "Delete folder?": "Удалить папку?", "Delete function?": "Удалить функцию?", @@ -829,6 +846,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Ошибка: Модель с ID '{{modelId}}' уже существует. Пожалуйста, выберите другой ID для продолжения.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Ошибка: ID модели не может быть пустым. Пожалуйста, введите корректный ID для продолжения.", "Evaluations": "Оценки", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Ключ API для Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Например: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Например: ALL", @@ -877,6 +898,7 @@ "Failed to connect to {{URL}} terminal server": "Не удалось подключиться к серверу терминала {{URL}}", "Failed to copy link": "Не удалось скопировать ссылку", "Failed to create API Key.": "Не удалось создать ключ API.", + "Failed to delete calendar": "", "Failed to delete note": "Не удалось удалить заметку", "Failed to download image": "Не удалось загрузить изображение", "Failed to extract content from the file: {{error}}": "Не удалось извлечь содержимое из файла: {{error}}", @@ -1198,6 +1220,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Лимит параллельных поисковых запросов. 0 = без ограничений (по умолчанию). Установите 1 для последовательного выполнения (рекомендуется для API со строгими лимитами, например, бесплатный тариф Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Ограничивает число параллельных запросов эмбеддингов. 0 — без ограничений.", "List": "Список", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Слушаю...", "Live": "Активно", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1231,7 @@ "local": "локально", "Local": "Локально", "Local Task Model": "Модель локальной задачи", + "Location": "", "Location access not allowed": "Доступ к местоположению запрещен", "Lost": "Поражение", "Low": "Низкий", @@ -1275,6 +1299,7 @@ "Model": "Модель", "Model '{{modelName}}' has been successfully downloaded.": "Модель '{{modelName}}' успешно загружена.", "Model '{{modelTag}}' is already in queue for downloading.": "Модель '{{modelTag}}' уже находится в очереди на загрузку.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Модель {{modelName}} не поддерживает зрение", "Model {{name}} is now {{status}}": "Модель {{name}} теперь {{status}}", @@ -1282,6 +1307,7 @@ "Model {{name}} is now visible": "Модель {{name}} теперь видна", "Model accepts file inputs": "Модель принимает входные данные файла", "Model accepts image inputs": "Модель принимает изображения как входные данные", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Модель может выполнять код и выполнять вычисления", "Model can generate images based on text prompts": "Модель может генерировать изображения на основе текстовых промптов", "Model can search the web for information": "Модель может искать информацию в Интернете", @@ -1315,6 +1341,7 @@ "Models Sharing": "Общий доступ к моделям", "Mojeek": "Mojeek", "Mojeek Search API Key": "Ключ API для поиска Mojeek", + "Month": "", "Monthly": "", "More": "Больше", "More Concise": "Более кратко", @@ -1333,6 +1360,7 @@ "New Automation": "", "New Button": "Новая кнопка", "New Chat": "Новый чат", + "New Event": "", "New File": "Новый файл", "New Folder": "Новая папка", "New Function": "Новая функция", @@ -1502,6 +1530,7 @@ "Password": "Пароль", "Passwords do not match.": "Пароли не совпадают.", "Paste Large Text as File": "Вставить большой текст как файл", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF-документ (.pdf)", "PDF Extract Images (OCR)": "Извлечение изображений из PDF (OCR)", @@ -1609,6 +1638,7 @@ "Reasoning Effort": "Усилия для рассуждения", "Reasoning Tags": "Теги рассуждения", "Recently Used": "", + "Reconnected": "", "Record": "Запись", "Record voice": "Записать голос", "Redirecting you to Open WebUI Community": "Перенаправляем вас в сообщество OpenWebUI", @@ -1632,6 +1662,7 @@ "Relevance": "Релевантность", "Relevance Threshold": "Порог релевантности", "Remember Dismissal": "Запомнить отклонение", + "Reminder": "", "Remove": "Удалить", "Remove {{MODELID}} from list.": "Удалить {{MODELID}} из списка.", "Remove action": "Удалить действие", @@ -1650,6 +1681,7 @@ "Reply to thread...": "Ответить в обсуждении...", "Replying to {{NAME}}": "Ответ для {{NAME}}", "required": "обязательно", + "Reranking Batch Size": "", "Reranking Engine": "Движок реранжирования", "Reranking Model": "Модель реранжирования", "Reset": "Сбросить", @@ -1879,7 +1911,13 @@ "Start a new conversation": "Начать новый разговор", "Start of the channel": "Начало канала", "Start Tag": "Начальный тег", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Запуск ядра...", + "Starting now": "", "State": "", "Status": "Статус", "Status cleared successfully": "Статус успешно очищен", @@ -1992,6 +2030,7 @@ "This will delete {{NAME}} and all its contents.": "При этом будет удален {{NAME}} и все его содержимое.", "This will delete all models including custom models": "Это приведет к удалению всех моделей, включая пользовательские модели.", "This will delete all models including custom models and cannot be undone.": "При этом будут удалены все модели, включая пользовательские, и это действие нельзя будет отменить.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Это сбросит базу знаний и синхронизирует все файлы. Хотите продолжить?", "Thorough explanation": "Подробное объяснение", "Thought": "Рассуждение", @@ -2011,6 +2050,7 @@ "Title cannot be an empty string.": "Заголовок не может быть пустой строкой.", "Title Generation": "Генерация заголовка", "Title Generation Prompt": "Промпт для генерации заголовка", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Чтобы получить доступ к доступным для загрузки названиям моделей,", "To access the GGUF models available for downloading,": "Чтобы получить доступ к моделям GGUF, доступным для загрузки,", @@ -2077,6 +2117,7 @@ "Unloads {{FROM_NOW}}": "Выгрузка из памяти {{FROM_NOW}}", "Unlock mysteries": "Разблокируйте тайны", "Unpin": "Открепить", + "Unpin from Sidebar": "", "Unravel secrets": "Разгадать секреты", "Unshare Chat": "Отменить публикацию чата", "Unsupported file type.": "Неподдерживаемый тип файла.", @@ -2181,6 +2222,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI будет отправлять запросы к \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI будет отправлять запросы к \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI будет отправлять запросы к \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Чего вы пытаетесь достичь?", "What are you working on?": "Над чем вы работаете?", @@ -2188,6 +2230,7 @@ "What is shared:": "Что передаётся:", "What's New in": "Что нового в", "What's on your mind?": "О чём хотите поговорить?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Если эта функция включена, модель будет отвечать на каждое сообщение чата в режиме реального времени, генерируя ответ, как только пользователь отправит сообщение. Этот режим полезен для приложений живого чата, но может повлиять на производительность на более медленном оборудовании.", "wherever you are": "где бы вы ни были", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Следует ли разбивать выходные данные на страницы. Каждая страница будет разделена горизонтальной линией и номером страницы. По умолчанию установлено значение Выкл.", diff --git a/src/lib/i18n/locales/sk-SK/translation.json b/src/lib/i18n/locales/sk-SK/translation.json index cfb4343e49..0ecf193014 100644 --- a/src/lib/i18n/locales/sk-SK/translation.json +++ b/src/lib/i18n/locales/sk-SK/translation.json @@ -35,8 +35,13 @@ "{{user}}'s Chats": "{{user}}'s konverzácie", "{{webUIName}} Backend Required": "Vyžaduje sa {{webUIName}} Backend", "*Prompt node ID(s) are required for image generation": "*Sú potrebné IDs pre prompt node na generovanie obrázkov", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Nová verzia (v{{LATEST_VERSION}}) je teraz k dispozícii.", @@ -49,6 +54,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Prístupné pre všetkých užívateľov", "Account": "Účet", "Account Activation Pending": "Čaká sa na aktiváciu účtu", @@ -74,9 +80,11 @@ "Add content here": "Pridať obsah sem", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Pridať súbory", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Pridať pamäť", @@ -112,6 +120,7 @@ "AI": "", "All": "Všetky", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Všetky modely úspešne odstránené", @@ -200,6 +209,7 @@ "Ask a question": "Opýtajte sa otázku", "Assistant": "Asistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "Pripojiť znalosti", @@ -274,6 +284,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "Volanie", "Call feature is not supported when using Web STT engine": "Funkcia volania nie je podporovaná pri použití Web STT engine.", "Camera": "Kamera", @@ -410,6 +422,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Pripojenia", @@ -441,6 +454,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Kopírovať odkaz", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Kopírovať do schránky", @@ -521,8 +535,11 @@ "Delete All Chats": "Odstrániť všetky konverzácie", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Odstrániť chat", "Delete chat?": "Odstrániť konverzáciu?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Odstrániť priečinok?", "Delete function?": "Funkcia na odstránenie?", @@ -829,6 +846,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Hodnotenia", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -877,6 +898,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Nepodarilo sa vytvoriť API kľúč.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1198,6 +1220,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Počúvanie...", "Live": "", "Llama.cpp": "", @@ -1208,6 +1231,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Stratený", "Low": "", @@ -1275,6 +1299,7 @@ "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "Model „{{modelName}}“ bol úspešne stiahnutý.", "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' je už zaradený do fronty na sťahovanie.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Model {{modelName}} nie je schopný spracovávať vizuálne údaje.", "Model {{name}} is now {{status}}": "Model {{name}} je teraz {{status}}.", @@ -1282,6 +1307,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "Model prijíma vstupy vo forme obrázkov", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1315,6 +1341,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Viac", "More Concise": "", @@ -1333,6 +1360,7 @@ "New Automation": "", "New Button": "", "New Chat": "Nový chat", + "New Event": "", "New File": "", "New Folder": "Nový priečinok", "New Function": "", @@ -1502,6 +1530,7 @@ "Password": "Heslo", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF dokument (.pdf)", "PDF Extract Images (OCR)": "Extrahovanie obrázkov z PDF (OCR)", @@ -1609,6 +1638,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Nahrať hlas", "Redirecting you to Open WebUI Community": "Presmerovanie na komunitu OpenWebUI", @@ -1632,6 +1662,7 @@ "Relevance": "Relevancia", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Odstrániť", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1650,6 +1681,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Model na prehodnotenie poradia", "Reset": "režim Reset", @@ -1879,7 +1911,13 @@ "Start a new conversation": "", "Start of the channel": "Začiatok kanála", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1992,6 +2030,7 @@ "This will delete {{NAME}} and all its contents.": "Týmto dôjde k odstráneniu {{NAME}} a všetkých jeho obsahov.", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Toto obnoví znalostnú databázu a synchronizuje všetky súbory. Prajete si pokračovať?", "Thorough explanation": "Obsiahle vysvetlenie", "Thought": "", @@ -2011,6 +2050,7 @@ "Title cannot be an empty string.": "Názov nemôže byť prázdny reťazec.", "Title Generation": "", "Title Generation Prompt": "Generovanie názvu promptu", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "Pre získanie dostupných názvov modelov na stiahnutie,", "To access the GGUF models available for downloading,": "Pre prístup k modelom GGUF dostupným na stiahnutie,", @@ -2077,6 +2117,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "Odopnúť", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2181,6 +2222,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Čo sa snažíte dosiahnuť?", "What are you working on?": "Na čom pracujete?", @@ -2188,6 +2230,7 @@ "What is shared:": "", "What's New in": "Čo je nové v", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "kdekoľvek ste", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/sr-RS/translation.json b/src/lib/i18n/locales/sr-RS/translation.json index 7e1b205850..647eb187b5 100644 --- a/src/lib/i18n/locales/sr-RS/translation.json +++ b/src/lib/i18n/locales/sr-RS/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Ћаскања корисника {{user}}", "{{webUIName}} Backend Required": "Захтева се {{webUIName}} позадинац", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -48,6 +53,7 @@ "Access Control": "Контрола приступа", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Доступно свим корисницима", "Account": "Налог", "Account Activation Pending": "Налози за активирање", @@ -73,9 +79,11 @@ "Add content here": "Додај садржај овде", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Додај датотеке", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Додај сећање", @@ -111,6 +119,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Сви модели су успешно обрисани", @@ -199,6 +208,7 @@ "Ask a question": "Постави питање", "Assistant": "Помоћник", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -273,6 +283,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "Позив", "Call feature is not supported when using Web STT engine": "", "Camera": "Камера", @@ -409,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Везе", @@ -440,6 +453,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Копирај везу", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Копирај у оставу", @@ -520,8 +534,11 @@ "Delete All Chats": "Обриши сва ћаскања", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Обриши ћаскање", "Delete chat?": "Обрисати ћаскање?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Обрисати фасциклу?", "Delete function?": "Обрисати функцију?", @@ -828,6 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Процењивања", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -876,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Неуспешно стварање API кључа.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1197,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Слушам...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1207,6 +1230,7 @@ "local": "", "Local": "Локално", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Пораза", "Low": "", @@ -1274,6 +1298,7 @@ "Model": "Модел", "Model '{{modelName}}' has been successfully downloaded.": "Модел „{{modelName}}“ је успешно преузет.", "Model '{{modelTag}}' is already in queue for downloading.": "Модел „{{modelTag}}“ је већ у реду за преузимање.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Модел {{моделНаме}} није способан за вид", "Model {{name}} is now {{status}}": "Модел {{наме}} је сада {{статус}}", @@ -1281,6 +1306,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1314,6 +1340,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Више", "More Concise": "", @@ -1332,6 +1359,7 @@ "New Automation": "", "New Button": "", "New Chat": "Ново ћаскање", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1501,6 +1529,7 @@ "Password": "Лозинка", "Passwords do not match.": "", "Paste Large Text as File": "Убаци велики текст као датотеку", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF документ (.pdf)", "PDF Extract Images (OCR)": "Извлачење PDF слика (OCR)", @@ -1608,6 +1637,7 @@ "Reasoning Effort": "Јачина размишљања", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Сними глас", "Redirecting you to Open WebUI Community": "Преусмеравање на OpenWebUI заједницу", @@ -1631,6 +1661,7 @@ "Relevance": "Примењивост", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Уклони", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1649,6 +1680,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Модел поновног рангирања", "Reset": "Поврати", @@ -1877,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "Почетак канала", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1990,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Ово ће обрисати {{NAME}} и сав садржај унутар.", "This will delete all models including custom models": "Ово ће обрисати све моделе укључујући прилагођене моделе", "This will delete all models including custom models and cannot be undone.": "Ово ће обрисати све моделе укључујући прилагођене моделе и не може се опозвати.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Ово ће обрисати базу знања и ускладити све датотеке. Да ли желите наставити?", "Thorough explanation": "Детаљно објашњење", "Thought": "", @@ -2009,6 +2047,7 @@ "Title cannot be an empty string.": "Наслов не може бити празан низ.", "Title Generation": "", "Title Generation Prompt": "Упит за стварање наслова", + "Title is required": "", "TLS": "ТЛС", "To access the available model names for downloading,": "Да бисте приступили доступним именима модела за преузимање,", "To access the GGUF models available for downloading,": "Да бисте приступили GGUF моделима доступним за преузимање,", @@ -2075,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Реши мистерије", "Unpin": "Откачи", + "Unpin from Sidebar": "", "Unravel secrets": "Разоткриј тајне", "Unshare Chat": "", "Unsupported file type.": "", @@ -2179,6 +2219,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2186,6 +2227,7 @@ "What is shared:": "", "What's New in": "Шта је ново у", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/sv-SE/translation.json b/src/lib/i18n/locales/sv-SE/translation.json index e097438fb6..9915d73f25 100644 --- a/src/lib/i18n/locales/sv-SE/translation.json +++ b/src/lib/i18n/locales/sv-SE/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}s Chattar", "{{webUIName}} Backend Required": "{{webUIName}} Backend krävs", "*Prompt node ID(s) are required for image generation": "*Prompt node ID(s) krävs för bildgenerering", + "1 hour before": "", "1 Source": "1 källa", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "En ny version (v{{LATEST_VERSION}}) är nu tillgänglig.", @@ -47,6 +52,7 @@ "Access Control": "Åtkomstkontroll", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Tillgänglig för alla användare", "Account": "Konto", "Account Activation Pending": "Kontoaktivering väntar", @@ -72,9 +78,11 @@ "Add content here": "Lägg till innehåll här", "Add Custom Parameter": "Lägg till anpassad parameter", "Add Custom Prompt": "", + "Add description": "", "Add Details": "Lägg till information", "Add Files": "Lägg till filer", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Lägg till minne", @@ -110,6 +118,7 @@ "AI": "", "All": "Alla", "All chats have been unarchived.": "Alla konversationer har avarkiverats.", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Alla modeller har raderats framgångsrikt", @@ -198,6 +207,7 @@ "Ask a question": "Ställ en fråga", "Assistant": "Assistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "Bifoga kunskap", @@ -272,6 +282,8 @@ "Bypass Web Loader": "Kringgå webbläsare", "Cache Base Model List": "", "Calendar": "Kalender", + "Calendar deleted": "", + "Calendars": "", "Call": "Samtal", "Call feature is not supported when using Web STT engine": "Samtalsfunktionen är inte kompatibel med Web Tal-till-text motor", "Camera": "Kamera", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Anslut till dina egna OpenAPI-kompatibla externa verktygsservrar.", "Connected ({{type}})": "", "Connection failed": "Anslutning misslyckades", + "Connection lost. Reconnecting...": "", "Connection successful": "Anslutning lyckades", "Connection Type": "Anslutningstyp", "Connections": "Anslutningar", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "Kopiera länk", "Copy Link": "Kopiera länk", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Kopiera till urklipp", @@ -519,8 +533,11 @@ "Delete All Chats": "Ta bort alla chattar", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Radera chatt", "Delete chat?": "Radera chatt?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Radera mapp?", "Delete function?": "Radera funktion?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Utvärderingar", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API-nyckel", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exempel: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exempel: ALLA", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Misslyckades med att kopiera länk", "Failed to create API Key.": "Misslyckades med att skapa API-nyckel.", + "Failed to delete calendar": "", "Failed to delete note": "Misslyckades med att ta bort anteckning", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Lyssnar...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "lokal", "Local": "Lokal", "Local Task Model": "Lokal uppgiftsmodell", + "Location": "", "Location access not allowed": "Åtkomst till platsen är inte tillåten", "Lost": "Förlorad", "Low": "Låg", @@ -1273,6 +1297,7 @@ "Model": "Modell", "Model '{{modelName}}' has been successfully downloaded.": "Modellen '{{modelName}}' har laddats ner.", "Model '{{modelTag}}' is already in queue for downloading.": "Modellen '{{modelTag}}' är redan i kö för nedladdning.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Modellen {{modelName}} har inte stöd för vision/syn", "Model {{name}} is now {{status}}": "Modellen {{name}} är nu {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "Modellen {{name}} är nu synlig", "Model accepts file inputs": "Modellen accepterar filinmatningar", "Model accepts image inputs": "Modellen accepterar bildinmatningar", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Modellen kan köra kod och utföra beräkningar", "Model can generate images based on text prompts": "Modellen kan generera bilder baserat på textprompter", "Model can search the web for information": "Modellen kan söka på webben efter information", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek Sök API-nyckel", + "Month": "", "Monthly": "", "More": "Mer", "More Concise": "Mer kortfattat", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "Ny knapp", "New Chat": "Ny chatt", + "New Event": "", "New File": "", "New Folder": "Ny mapp", "New Function": "Ny funktion", @@ -1500,6 +1528,7 @@ "Password": "Lösenord", "Passwords do not match.": "Lösenorden matchar inte.", "Paste Large Text as File": "Klistra in stor text som fil", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF-dokument (.pdf)", "PDF Extract Images (OCR)": "PDF Extrahera bilder (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Resonemangsinsats", "Reasoning Tags": "Resonemangs-taggar (tags)", "Recently Used": "", + "Reconnected": "", "Record": "Spela in", "Record voice": "Spela in röst", "Redirecting you to Open WebUI Community": "Omdirigerar dig till OpenWebUI Community", @@ -1630,6 +1660,7 @@ "Relevance": "Relevans", "Relevance Threshold": "Relevanströskel", "Remember Dismissal": "Kom ihåg avvisning", + "Reminder": "", "Remove": "Ta bort", "Remove {{MODELID}} from list.": "Ta bort {{MODELID}} från listan.", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "Svara i tråd...", "Replying to {{NAME}}": "Svarar {{NAME}}", "required": "obligatoriskt", + "Reranking Batch Size": "", "Reranking Engine": "Omrankningsmotor", "Reranking Model": "Reranking modell", "Reset": "Återställ", @@ -1875,7 +1907,11 @@ "Start a new conversation": "Starta en ny konversation", "Start of the channel": "Början av kanalen", "Start Tag": "Starta en tagg", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Detta kommer att radera {{NAME}} och allt dess innehåll.", "This will delete all models including custom models": "Detta kommer att radera alla modeller inklusive anpassade modeller", "This will delete all models including custom models and cannot be undone.": "Detta kommer att radera alla modeller inklusive anpassade modeller och kan inte ångras.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Detta kommer att återställa kunskapsbasen och synkronisera alla filer. Vill du fortsätta?", "Thorough explanation": "Djupare förklaring", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Titeln får inte vara en tom sträng.", "Title Generation": "Titelgenerering", "Title Generation Prompt": "Instruktion för titelgenerering", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "För att komma åt de tillgängliga modellnamnen för nedladdning,", "To access the GGUF models available for downloading,": "För att komma åt de GGUF-modellerna som finns tillgängliga för nedladdning,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "Avlastar {{FROM_NOW}}", "Unlock mysteries": "Lås upp mysterier", "Unpin": "Ta bort fästning", + "Unpin from Sidebar": "", "Unravel secrets": "Avslöja hemligheter", "Unshare Chat": "", "Unsupported file type.": "Filtypen stöds inte.", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI kommer att göra förfrågningar till \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI kommer att göra förfrågningar till \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI kommer att göra förfrågningar till \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Vad försöker du uppnå?", "What are you working on?": "Var arbetar du med?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "Vad är nytt i", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "När det här läget är aktiverat svarar modellen på varje chattmeddelande i realtid och genererar ett svar så snart användaren skickar ett meddelande. Det här läget är användbart för livechattar, men kan påverka prestandan på långsammare maskinvara.", "wherever you are": "var du än befinner dig", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Om utdata ska sidnumreras. Varje sida kommer att separeras av en horisontell linje och sidnummer. Standardvärdet är False.", diff --git a/src/lib/i18n/locales/ta-IN/translation.json b/src/lib/i18n/locales/ta-IN/translation.json index 4f773125d6..646aec1471 100644 --- a/src/lib/i18n/locales/ta-IN/translation.json +++ b/src/lib/i18n/locales/ta-IN/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} இன் அரட்டைகள்", "{{webUIName}} Backend Required": "{{webUIName}} பின்தளம் தேவை", "*Prompt node ID(s) are required for image generation": "*பட உருவாக்கத்திற்கு உடனடி முனை ID(கள்) தேவை", + "1 hour before": "", "1 Source": "1 ஆதாரம்", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1 நிமிடம் முன்", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "மக்கள் உறுப்பினர்களாக சேரும் ஒத்துழைப்பு சேனல்", "A discussion channel where access is controlled by groups and permissions": "குழுக்கள் மற்றும் அனுமதிகளால் அணுகல் கட்டுப்படுத்தப்படும் விவாத சேனல்", "A new version (v{{LATEST_VERSION}}) is now available.": "புதிய பதிப்பு (v{{LATEST_VERSION}}) இப்போது கிடைக்கிறது.", @@ -47,6 +52,7 @@ "Access Control": "அணுகல் கட்டுப்பாடு", "Access Grants": "அணுகல் மானியங்கள்", "Access List": "அணுகல் பட்டியல்", + "Access updated": "", "Accessible to all users": "அனைத்து பயனர்களுக்கும் அணுகக்கூடியது", "Account": "கணக்கு", "Account Activation Pending": "கணக்கு செயல்படுத்தல் நிலுவையில் உள்ளது", @@ -72,9 +78,11 @@ "Add content here": "உள்ளடக்கத்தை இங்கே சேர்க்கவும்", "Add Custom Parameter": "தனிப்பயன் அளவுருவைச் சேர்க்கவும்", "Add Custom Prompt": "தனிப்பயன் வரியில் சேர்க்கவும்", + "Add description": "", "Add Details": "விவரங்களைச் சேர்க்கவும்", "Add Files": "கோப்புகளைச் சேர்க்கவும்", "Add Image": "படத்தைச் சேர்க்கவும்", + "Add location": "", "Add Member": "உறுப்பினரைச் சேர்க்கவும்", "Add Members": "உறுப்பினர்களைச் சேர்க்கவும்", "Add Memory": "நினைவகத்தைச் சேர்க்கவும்", @@ -110,6 +118,7 @@ "AI": "AI", "All": "அனைத்தும்", "All chats have been unarchived.": "அனைத்து அரட்டைகளும் மீட்டெடுக்கப்பட்டன.", + "All day": "", "All models are now hidden": "அனைத்து மாடல்களும் இப்போது மறைக்கப்பட்டுள்ளன", "All models are now visible": "அனைத்து மாடல்களும் இப்போது தெரியும்", "All models deleted successfully": "அனைத்து மாடல்களும் வெற்றிகரமாக நீக்கப்பட்டன", @@ -198,6 +207,7 @@ "Ask a question": "ஒரு கேள்வி கேளுங்கள்", "Assistant": "உதவியாளர்", "Async Embedding Processing": "ஒத்திசைவு உட்பொதித்தல் செயலாக்கம்", + "At time of event": "", "Attach File From Knowledge": "அறிவிலிருந்து கோப்பை இணைக்கவும்", "Attach Files": "கோப்புகளை இணைக்கவும்", "Attach Knowledge": "அறிவை இணைக்கவும்", @@ -272,6 +282,8 @@ "Bypass Web Loader": "பைபாஸ் இணைய ஏற்றி", "Cache Base Model List": "கேச் அடிப்படை மாதிரி பட்டியல்", "Calendar": "நாட்காட்டி", + "Calendar deleted": "", + "Calendars": "", "Call": "அழைக்கவும்", "Call feature is not supported when using Web STT engine": "Web STT இன்ஜினைப் பயன்படுத்தும் போது அழைப்பு அம்சம் ஆதரிக்கப்படாது", "Camera": "கேமரா", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "உங்கள் சொந்த OpenAPI இணக்கமான வெளிப்புற கருவி சேவையகங்களுடன் இணைக்கவும்.", "Connected ({{type}})": "இணைக்கப்பட்டது ({{type}})", "Connection failed": "இணைப்பு தோல்வியடைந்தது", + "Connection lost. Reconnecting...": "", "Connection successful": "இணைப்பு வெற்றிகரமாக உள்ளது", "Connection Type": "இணைப்பு வகை", "Connections": "இணைப்புகள்", @@ -439,6 +452,7 @@ "Copy Last Response": "கடைசி பதிலை நகலெடுக்கவும்", "Copy link": "இணைப்பை நகலெடுக்கவும்", "Copy Link": "இணைப்பை நகலெடுக்கவும்", + "Copy Path": "", "Copy Prompt": "நகலெடுக்கவும்", "Copy Share Link": "பகிர்வு இணைப்பை நகலெடுக்கவும்", "Copy to clipboard": "கிளிப்போர்டுக்கு நகலெடுக்கவும்", @@ -519,8 +533,11 @@ "Delete All Chats": "அனைத்து அரட்டைகளையும் நீக்கு", "Delete all contents inside this folder": "இந்தக் கோப்புறையில் உள்ள அனைத்து உள்ளடக்கங்களையும் நீக்கவும்", "Delete automation?": "தானியக்கத்தை நீக்கவா?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "அரட்டையை நீக்கு", "Delete chat?": "அரட்டையை நீக்கவா?", + "Delete Event": "", "Delete File": "கோப்பை நீக்கு", "Delete folder?": "கோப்புறையை நீக்கவா?", "Delete function?": "செயல்பாட்டை நீக்கவா?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "பிழை: ID '{{modelId}}' உடன் ஒரு மாதிரி ஏற்கனவே உள்ளது. தொடர வேறு ID ஐத் தேர்ந்தெடுக்கவும்.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "பிழை: மாடல் ID காலியாக இருக்க முடியாது. தொடர சரியான ID ஐ உள்ளிடவும்.", "Evaluations": "மதிப்பீடுகள்", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API விசை", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "எடுத்துக்காட்டு: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "எடுத்துக்காட்டு: ALL", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "{{URL}} டெர்மினல் சர்வருடன் இணைக்க முடியவில்லை", "Failed to copy link": "இணைப்பை நகலெடுக்க முடியவில்லை", "Failed to create API Key.": "API விசையை உருவாக்குவதில் தோல்வி.", + "Failed to delete calendar": "", "Failed to delete note": "குறிப்பை நீக்க முடியவில்லை", "Failed to download image": "படத்தைப் பதிவிறக்க முடியவில்லை", "Failed to extract content from the file: {{error}}": "கோப்பிலிருந்து உள்ளடக்கத்தைப் பிரித்தெடுக்க முடியவில்லை: {{error}}", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "ஒரே நேரத்தில் தேடல் வினவல்களை வரம்பிடவும். 0 = வரம்பற்றது (இயல்புநிலை). தொடர்ச்சியான செயல்பாட்டிற்கு 1 என அமைக்கவும் (பிரேவ் ஃப்ரீ டையர் போன்ற கடுமையான விகித வரம்புகளைக் கொண்ட API களுக்குப் பரிந்துரைக்கப்படுகிறது).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "ஒரே நேரத்தில் உட்பொதித்தல் கோரிக்கைகளின் எண்ணிக்கையைக் கட்டுப்படுத்துகிறது. வரம்பற்ற 0 என அமைக்கவும்.", "List": "பட்டியல்", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "கேட்கிறது...", "Live": "வாழ்க", "Llama.cpp": "லாமா.சிபிபி", @@ -1206,6 +1229,7 @@ "local": "உள்ளூர்", "Local": "உள்ளூர்", "Local Task Model": "உள்ளூர் பணி மாதிரி", + "Location": "", "Location access not allowed": "இருப்பிட அணுகல் அனுமதிக்கப்படவில்லை", "Lost": "இழந்தது", "Low": "குறைந்த", @@ -1273,6 +1297,7 @@ "Model": "மாதிரி", "Model '{{modelName}}' has been successfully downloaded.": "மாடல் '{{modelName}}' வெற்றிகரமாகப் பதிவிறக்கப்பட்டது.", "Model '{{modelTag}}' is already in queue for downloading.": "மாடல் '{{modelTag}}' ஏற்கனவே பதிவிறக்குவதற்கு வரிசையில் உள்ளது.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "மாதிரி {{modelName}} வெற்றிகரமாக நீக்கப்பட்டது", "Model {{modelName}} is not vision capable": "மாதிரி {{modelName}} பார்வை திறன் இல்லை", "Model {{name}} is now {{status}}": "மாடல் {{name}} இப்போது {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "மாடல் {{name}} இப்போது தெரியும்", "Model accepts file inputs": "மாதிரி கோப்பு உள்ளீடுகளை ஏற்றுக்கொள்கிறது", "Model accepts image inputs": "மாடல் பட உள்ளீடுகளை ஏற்றுக்கொள்கிறது", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "மாதிரி குறியீட்டை இயக்கலாம் மற்றும் கணக்கீடுகளைச் செய்யலாம்", "Model can generate images based on text prompts": "மாதிரியானது உரைத் தூண்டுதல்களின் அடிப்படையில் படங்களை உருவாக்க முடியும்", "Model can search the web for information": "மாடல் தகவல்களை இணையத்தில் தேடலாம்", @@ -1313,6 +1339,7 @@ "Models Sharing": "மாதிரிகள் பகிர்வு", "Mojeek": "மொஜீக்", "Mojeek Search API Key": "Mojeek தேடல் API விசை", + "Month": "", "Monthly": "", "More": "மேலும்", "More Concise": "மேலும் சுருக்கமானது", @@ -1331,6 +1358,7 @@ "New Automation": "புதிய தானியக்கம்", "New Button": "புதிய பொத்தான்", "New Chat": "புதிய அரட்டை", + "New Event": "", "New File": "புதிய கோப்பு", "New Folder": "புதிய கோப்புறை", "New Function": "புதிய செயல்பாடு", @@ -1500,6 +1528,7 @@ "Password": "கடவுச்சொல்", "Passwords do not match.": "கடவுச்சொற்கள் பொருந்தவில்லை.", "Paste Large Text as File": "பெரிய உரையை கோப்பாக ஒட்டவும்", + "Path copied": "", "Paused": "இடைநிறுத்தப்பட்டது", "PDF document (.pdf)": "PDF ஆவணம் (.pdf)", "PDF Extract Images (OCR)": "PDF படங்களை பிரித்தெடுக்கவும் (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "பகுத்தறிவு முயற்சி", "Reasoning Tags": "பகுத்தறிவு குறிச்சொற்கள்", "Recently Used": "சமீபத்தில் பயன்படுத்தப்பட்டது", + "Reconnected": "", "Record": "பதிவு", "Record voice": "குரல் பதிவு", "Redirecting you to Open WebUI Community": "உங்களை Open WebUI சமூகத்திற்கு திருப்பி விடுகிறோம்", @@ -1630,6 +1660,7 @@ "Relevance": "சம்பந்தம்", "Relevance Threshold": "சம்பந்தமான வரம்பு", "Remember Dismissal": "பணிநீக்கம் என்பதை நினைவில் கொள்க", + "Reminder": "", "Remove": "அகற்று", "Remove {{MODELID}} from list.": "பட்டியலில் இருந்து {{MODELID}} ஐ அகற்று.", "Remove action": "செயலை அகற்று", @@ -1648,6 +1679,7 @@ "Reply to thread...": "திரிக்கு பதில்...", "Replying to {{NAME}}": "{{NAME}} க்கு பதிலளிக்கிறது", "required": "தேவை", + "Reranking Batch Size": "", "Reranking Engine": "மறுவரிசைப்படுத்தல் இயந்திரம்", "Reranking Model": "மறுவரிசைப்படுத்தல் மாதிரி", "Reset": "மீட்டமை", @@ -1875,7 +1907,11 @@ "Start a new conversation": "புதிய உரையாடலைத் தொடங்கவும்", "Start of the channel": "சேனலின் ஆரம்பம்", "Start Tag": "தொடக்க குறிச்சொல்", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "கர்னலைத் தொடங்குகிறது...", + "Starting now": "", "State": "நிலை", "Status": "நிலை", "Status cleared successfully": "நிலை வெற்றிகரமாக அழிக்கப்பட்டது", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "இது {{NAME}} மற்றும் அதன் அனைத்து உள்ளடக்கங்களையும் நீக்கும்.", "This will delete all models including custom models": "இது தனிப்பயன் மாதிரிகள் உட்பட அனைத்து மாடல்களையும் நீக்கும்", "This will delete all models including custom models and cannot be undone.": "இது தனிப்பயன் மாதிரிகள் உட்பட அனைத்து மாடல்களையும் நீக்கிவிடும், மேலும் செயல்தவிர்க்க முடியாது.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "இது அறிவுத் தளத்தை மீட்டமைத்து அனைத்து கோப்புகளையும் ஒத்திசைக்கும். நீங்கள் தொடர விரும்புகிறீர்களா?", "Thorough explanation": "விரிவான விளக்கம்", "Thought": "சிந்தனை", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "தலைப்பு வெற்று சரமாக இருக்கக்கூடாது.", "Title Generation": "தலைப்பு தலைமுறை", "Title Generation Prompt": "தலைப்பு உருவாக்கத் தூண்டுதல்", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "பதிவிறக்குவதற்கு கிடைக்கக்கூடிய மாதிரி பெயர்களை அணுக,", "To access the GGUF models available for downloading,": "பதிவிறக்குவதற்கு கிடைக்கும் GGUF மாதிரிகளை அணுக,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} இறக்குகிறது", "Unlock mysteries": "மர்மங்களைத் திறக்கவும்", "Unpin": "அன்பின்", + "Unpin from Sidebar": "", "Unravel secrets": "இரகசியங்களை அவிழ்த்து விடுங்கள்", "Unshare Chat": "அரட்டையைப் பகிர்வதை நீக்கு", "Unsupported file type.": "ஆதரிக்கப்படாத கோப்பு வகை.", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI \"{{url}}\" க்கு கோரிக்கைகளை வைக்கும்", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI \"{{url}}/api/chat\" க்கு கோரிக்கைகளை வைக்கும்", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" க்கு கோரிக்கைகளை வைக்கும்", + "Week": "", "Weekly": "", "What are you trying to achieve?": "நீங்கள் எதை அடைய முயற்சிக்கிறீர்கள்?", "What are you working on?": "நீங்கள் என்ன வேலை செய்கிறீர்கள்?", @@ -2184,6 +2224,7 @@ "What is shared:": "என்ன பகிரப்படுகிறது:", "What's New in": "இதில் புதிதாக என்ன இருக்கிறது", "What's on your mind?": "உங்கள் மனதில் என்ன இருக்கிறது?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "இயக்கப்பட்டால், மாடல் ஒவ்வொரு அரட்டை செய்திக்கும் நிகழ்நேரத்தில் பதிலளிக்கும், பயனர் செய்தியை அனுப்பியவுடன் பதிலை உருவாக்கும். நேரடி அரட்டை பயன்பாடுகளுக்கு இந்த பயன்முறை பயனுள்ளதாக இருக்கும், ஆனால் மெதுவான வன்பொருளில் செயல்திறனை பாதிக்கலாம்.", "wherever you are": "நீங்கள் எங்கிருந்தாலும்", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "வெளியீட்டை பக்கமாக்க வேண்டுமா. ஒவ்வொரு பக்கமும் கிடைமட்ட விதி மற்றும் பக்க எண்ணால் பிரிக்கப்படும். இயல்புநிலையிலிருந்து தவறு.", diff --git a/src/lib/i18n/locales/th-TH/translation.json b/src/lib/i18n/locales/th-TH/translation.json index d337319a8b..17dd64ef45 100644 --- a/src/lib/i18n/locales/th-TH/translation.json +++ b/src/lib/i18n/locales/th-TH/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "การแชทของ {{user}}", "{{webUIName}} Backend Required": "ต้องใช้ Backend ของ {{webUIName}}", "*Prompt node ID(s) are required for image generation": "*ต้องระบุ ID ของ prompt node สำหรับการสร้างภาพ", + "1 hour before": "", "1 Source": "1 แหล่งที่มา", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "เวอร์ชันใหม่ (v{{LATEST_VERSION}}) พร้อมให้ใช้งานแล้ว", @@ -46,6 +51,7 @@ "Access Control": "การควบคุมการเข้าถึง", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "เข้าถึงได้สำหรับผู้ใช้ทั้งหมด", "Account": "บัญชี", "Account Activation Pending": "การเปิดใช้งานบัญชีกำลังดำเนินการ", @@ -71,9 +77,11 @@ "Add content here": "เพิ่มเนื้อหาตรงนี้", "Add Custom Parameter": "เพิ่มพารามิเตอร์ที่กำหนดเอง", "Add Custom Prompt": "เพิ่มพรอมต์ที่กำหนดเอง", + "Add description": "", "Add Details": "เพิ่มรายละเอียด", "Add Files": "เพิ่มไฟล์", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "เพิ่มความจำ", @@ -109,6 +117,7 @@ "AI": "AI", "All": "ทั้งหมด", "All chats have been unarchived.": "ยกเลิกการเก็บถาวรการแชททั้งหมดแล้ว", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "ลบโมเดลทั้งหมดเรียบร้อยแล้ว", @@ -197,6 +206,7 @@ "Ask a question": "ถามคำถาม", "Assistant": "ผู้ช่วย", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "แนบไฟล์จากฐานความรู้", "Attach Files": "", "Attach Knowledge": "แนบฐานความรู้", @@ -271,6 +281,8 @@ "Bypass Web Loader": "ข้ามตัวโหลดเว็บไซต์", "Cache Base Model List": "แคชรายการโมเดลพื้นฐาน", "Calendar": "ปฏิทิน", + "Calendar deleted": "", + "Calendars": "", "Call": "โทร", "Call feature is not supported when using Web STT engine": "ไม่รองรับฟีเจอร์การโทรเมื่อใช้เอนจิน Web STT", "Camera": "กล้อง", @@ -407,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "เชื่อมต่อกับเซิร์ฟเวอร์เครื่องมือภายนอกของคุณที่รองรับ OpenAPI", "Connected ({{type}})": "", "Connection failed": "การเชื่อมต่อล้มเหลว", + "Connection lost. Reconnecting...": "", "Connection successful": "เชื่อมต่อสำเร็จ", "Connection Type": "ประเภทการเชื่อมต่อ", "Connections": "การเชื่อมต่อ", @@ -438,6 +451,7 @@ "Copy Last Response": "คัดลอกคำตอบล่าสุด", "Copy link": "คัดลอกลิงก์", "Copy Link": "คัดลอกลิงก์", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "คัดลอกไปยังคลิปบอร์ด", @@ -518,8 +532,11 @@ "Delete All Chats": "ลบการแชททั้งหมด", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "ลบแชท", "Delete chat?": "ลบแชท?", + "Delete Event": "", "Delete File": "", "Delete folder?": "ลบโฟลเดอร์ใช่หรือไม่?", "Delete function?": "ลบฟังก์ชัน?", @@ -826,6 +843,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "ข้อผิดพลาด: มีโมเดลที่ใช้ ID '{{modelId}}' อยู่แล้ว โปรดเลือก ID อื่นเพื่อดำเนินการต่อ", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "ข้อผิดพลาด: ห้ามปล่อย ID โมเดลว่างไว้ กรุณากรอก ID ที่ถูกต้องเพื่อดำเนินการต่อ", "Evaluations": "การประเมิน", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "API Key ของ Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "ตัวอย่าง: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "ตัวอย่าง: ทั้งหมด", @@ -874,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "คัดลอกลิงก์ไม่สำเร็จ", "Failed to create API Key.": "สร้าง API Key ล้มเหลว", + "Failed to delete calendar": "", "Failed to delete note": "ลบบันทึกไม่สำเร็จ", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "ไม่สามารถดึงเนื้อหาจากไฟล์ได้: {{error}}", @@ -1195,6 +1217,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "กำลังฟัง...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1205,6 +1228,7 @@ "local": "ภายในเครื่อง", "Local": "ในเครื่อง", "Local Task Model": "โมเดลงานบนเครื่อง", + "Location": "", "Location access not allowed": "ไม่อนุญาตให้เข้าถึงตำแหน่งที่ตั้ง", "Lost": "หาย", "Low": "ต่ำ", @@ -1272,6 +1296,7 @@ "Model": "โมเดล", "Model '{{modelName}}' has been successfully downloaded.": "โมเดล '{{modelName}}' ถูกดาวน์โหลดเรียบร้อยแล้ว", "Model '{{modelTag}}' is already in queue for downloading.": "โมเดล '{{modelTag}}' อยู่ในคิวสำหรับการดาวน์โหลดแล้ว", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "โมเดล {{modelName}} ไม่รองรับฟีเจอร์ Vision", "Model {{name}} is now {{status}}": "โมเดล {{name}} ขณะนี้ {{status}}", @@ -1279,6 +1304,7 @@ "Model {{name}} is now visible": "โมเดล {{name}} มองเห็นได้แล้ว", "Model accepts file inputs": "โมเดลรองรับการป้อนข้อมูลจากไฟล์", "Model accepts image inputs": "โมเดลรองรับอินพุตรูปภาพ", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "โมเดลสามารถรันโค้ดและคำนวณได้", "Model can generate images based on text prompts": "โมเดลสามารถสร้างภาพจากพรอมต์ข้อความได้", "Model can search the web for information": "โมเดลสามารถค้นหาข้อมูลจากเว็บได้", @@ -1312,6 +1338,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "API Key สำหรับ Mojeek Search", + "Month": "", "Monthly": "", "More": "เพิ่มเติม", "More Concise": "กระชับมากขึ้น", @@ -1330,6 +1357,7 @@ "New Automation": "", "New Button": "ปุ่มใหม่", "New Chat": "แชทใหม่", + "New Event": "", "New File": "", "New Folder": "โฟลเดอร์ใหม่", "New Function": "ฟังก์ชันใหม่", @@ -1499,6 +1527,7 @@ "Password": "รหัสผ่าน", "Passwords do not match.": "รหัสผ่านไม่ตรงกัน", "Paste Large Text as File": "วางข้อความขนาดใหญ่เป็นไฟล์", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "เอกสาร PDF (.pdf)", "PDF Extract Images (OCR)": "การดึงรูปภาพจาก PDF (OCR)", @@ -1606,6 +1635,7 @@ "Reasoning Effort": "ระดับการใช้เหตุผล", "Reasoning Tags": "ป้ายกำกับการให้เหตุผล", "Recently Used": "", + "Reconnected": "", "Record": "บันทึก", "Record voice": "บันทึกเสียง", "Redirecting you to Open WebUI Community": "กำลังเปลี่ยนเส้นทางคุณไปยังชุมชน Open WebUI", @@ -1629,6 +1659,7 @@ "Relevance": "ความเกี่ยวข้อง", "Relevance Threshold": "เกณฑ์ความเกี่ยวข้อง", "Remember Dismissal": "จำการปิดข้อความ", + "Reminder": "", "Remove": "ลบ", "Remove {{MODELID}} from list.": "ลบ {{MODELID}} ออกจากรายการ", "Remove action": "", @@ -1647,6 +1678,7 @@ "Reply to thread...": "ตอบกลับเธรด...", "Replying to {{NAME}}": "กำลังตอบกลับ {{NAME}}", "required": "จำเป็น", + "Reranking Batch Size": "", "Reranking Engine": "เอนจิน Reranking", "Reranking Model": "โมเดล Reranking", "Reset": "รีเซ็ต", @@ -1873,7 +1905,10 @@ "Start a new conversation": "เริ่มการสนทนาใหม่", "Start of the channel": "จุดเริ่มต้นของช่อง", "Start Tag": "แท็กเริ่มต้น", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1986,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "การดำเนินการนี้จะลบ {{NAME}} และเนื้อหาทั้งหมด", "This will delete all models including custom models": "การดำเนินการนี้จะลบโมเดลทั้งหมด รวมถึงโมเดลแบบกำหนดเอง", "This will delete all models including custom models and cannot be undone.": "การดำเนินการนี้จะลบโมเดลทั้งหมดรวมถึงโมเดลที่กำหนดเอง และไม่สามารถยกเลิกได้", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "การดำเนินการนี้จะรีเซ็ตฐานความรู้และซิงค์ไฟล์ทั้งหมด คุณต้องการดำเนินการต่อหรือไม่?", "Thorough explanation": "คำอธิบายอย่างละเอียด", "Thought": "", @@ -2005,6 +2041,7 @@ "Title cannot be an empty string.": "ชื่อเรื่องต้องไม่เป็นสตริงว่าง", "Title Generation": "การสร้างชื่อเรื่อง", "Title Generation Prompt": "พรอมต์สำหรับสร้างชื่อเรื่อง", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "ในการเข้าถึงชื่อโมเดลที่มีให้ดาวน์โหลดนั้น", "To access the GGUF models available for downloading,": "ในการเข้าถึงโมเดล GGUF ที่มีให้ดาวน์โหลดได้", @@ -2071,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "ยกเลิกการใช้งาน {{FROM_NOW}}", "Unlock mysteries": "ไขปริศนา", "Unpin": "ยกเลิกการปักหมุด", + "Unpin from Sidebar": "", "Unravel secrets": "เปิดเผยความลับ", "Unshare Chat": "", "Unsupported file type.": "ไม่รองรับไฟล์ประเภทนี้", @@ -2175,6 +2213,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI จะส่งคำขอไปยัง \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI จะส่งคำขอไปที่ \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI จะส่งคำขอไปยัง \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "คุณพยายามจะทำอะไร?", "What are you working on?": "คุณกำลังทำอะไรอยู่?", @@ -2182,6 +2221,7 @@ "What is shared:": "", "What's New in": "มีอะไรใหม่ใน", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "เมื่อเปิดใช้งาน โมเดลจะตอบกลับแต่ละข้อความแชทแบบเรียลไทม์ โดยสร้างคำตอบทันทีที่ผู้ใช้ส่งข้อความ โหมดนี้มีประโยชน์สำหรับแอปแชทแบบสด แต่อาจส่งผลต่อประสิทธิภาพบนฮาร์ดแวร์ที่ทำงานช้า", "wherever you are": "ไม่ว่าคุณจะอยู่ที่ไหน", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "ว่าจะแบ่งหน้าผลลัพธ์หรือไม่ แต่ละหน้าจะถูกแยกด้วยเส้นแบ่งแนวนอนและหมายเลขหน้า ค่าเริ่มต้นคือ False", diff --git a/src/lib/i18n/locales/tk-TM/translation.json b/src/lib/i18n/locales/tk-TM/translation.json index cb777190b4..6783a0222a 100644 --- a/src/lib/i18n/locales/tk-TM/translation.json +++ b/src/lib/i18n/locales/tk-TM/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}'iň Çatlary", "{{webUIName}} Backend Required": "{{webUIName}} Backend Zerur", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -47,6 +52,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "Hasap", "Account Activation Pending": "", @@ -72,9 +78,11 @@ "Add content here": "", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Faýllar goş", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Ýat goş", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -198,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", "Camera": "", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Baglanyşyklar", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Baglanyşygy Göçür", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "", @@ -519,8 +533,11 @@ "Delete All Chats": "Ähli Çatlary Öçür", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "", "Delete chat?": "", + "Delete Event": "", "Delete File": "", "Delete folder?": "", "Delete function?": "", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "", "Live": "", "Llama.cpp": "", @@ -1206,6 +1229,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "", "Model '{{modelTag}}' is already in queue for downloading.": "", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "", "Model {{name}} is now {{status}}": "", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "Has köp", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "Parol", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "", "PDF Extract Images (OCR)": "", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "", "Redirecting you to Open WebUI Community": "", @@ -1630,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Aýyr", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "", "Reset": "Täzeden Guruň", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Kanal başy", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "", "Title Generation": "", "Title Generation Prompt": "", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "", "To access the GGUF models available for downloading,": "", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/tr-TR/translation.json b/src/lib/i18n/locales/tr-TR/translation.json index 62350354d5..5b31954239 100644 --- a/src/lib/i18n/locales/tr-TR/translation.json +++ b/src/lib/i18n/locales/tr-TR/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}'ın Sohbetleri", "{{webUIName}} Backend Required": "{{webUIName}} Arka-uç Gerekli", "*Prompt node ID(s) are required for image generation": "*Görüntü oluşturma için düğüm ID'leri gereklidir", + "1 hour before": "", "1 Source": "1 Kaynak", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1 dk önce", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "İnsanların üye olarak katıldığı bir iş birliği kanalı", "A discussion channel where access is controlled by groups and permissions": "Erişimin gruplar ve izinlerle kontrol edildiği bir tartışma kanalı", "A new version (v{{LATEST_VERSION}}) is now available.": "Yeni bir sürüm (v{{LATEST_VERSION}}) artık mevcut.", @@ -47,6 +52,7 @@ "Access Control": "Erişim Kontrolü", "Access Grants": "Erişim İzinleri", "Access List": "Erişim Listesi", + "Access updated": "", "Accessible to all users": "Tüm kullanıcılara erişilebilir", "Account": "Hesap", "Account Activation Pending": "Hesap Aktivasyonu Bekleniyor", @@ -72,9 +78,11 @@ "Add content here": "Buraya içerik ekleyin", "Add Custom Parameter": "Özel Parametre Ekle", "Add Custom Prompt": "Özel Prompt Ekle", + "Add description": "", "Add Details": "Ayrıntı Ekle", "Add Files": "Dosyalar Ekle", "Add Image": "Görsel Ekle", + "Add location": "", "Add Member": "Üye Ekle", "Add Members": "Üyeleri Ekle", "Add Memory": "Bellek Ekle", @@ -110,6 +118,7 @@ "AI": "Yapay Zeka", "All": "Tüm", "All chats have been unarchived.": "Tüm sohbetler arşivden çıkarıldı.", + "All day": "", "All models are now hidden": "Tüm modeller artık gizli", "All models are now visible": "Tüm modeller artık görünür", "All models deleted successfully": "Tüm modeller başarıyla silindi", @@ -198,6 +207,7 @@ "Ask a question": "Bir soru sorun", "Assistant": "Asistan", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "Bilgi Tabanından Dosya Ekle", "Attach Files": "", "Attach Knowledge": "Bilgi Tabanı Ekle", @@ -272,6 +282,8 @@ "Bypass Web Loader": "Web Yükleyicisini Atla", "Cache Base Model List": "Temel Model Listesini Önbelleğe Al", "Calendar": "Takvim", + "Calendar deleted": "", + "Calendars": "", "Call": "Arama", "Call feature is not supported when using Web STT engine": "Web STT motoru kullanılırken arama özelliği desteklenmiyor", "Camera": "Kamera", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Kendi OpenAPI uyumlu harici araç sunucularınıza bağlanın.", "Connected ({{type}})": "", "Connection failed": "Bağlantı başarısız", + "Connection lost. Reconnecting...": "", "Connection successful": "Bağlantı başarılı", "Connection Type": "Bağlantı Tipi", "Connections": "Bağlantılar", @@ -439,6 +452,7 @@ "Copy Last Response": "Son Yanıtı Kopyala", "Copy link": "Bağlantıyı kopyala", "Copy Link": "Bağlantıyı Kopyala", + "Copy Path": "", "Copy Prompt": "Prompt'u Kopyala", "Copy Share Link": "", "Copy to clipboard": "Panoya kopyala", @@ -519,8 +533,11 @@ "Delete All Chats": "Tüm Sohbetleri Sil", "Delete all contents inside this folder": "Bu klasördeki tüm içerikleri sil", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Sohbeti Sil", "Delete chat?": "Sohbeti sil?", + "Delete Event": "", "Delete File": "Dosyayı Sil", "Delete folder?": "Klasörü sil?", "Delete function?": "Fonksiyonu sil?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Hata: '{{modelId}}' ID'sine sahip bir model zaten mevcut. Devam etmek için lütfen farklı bir ID seçin.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Hata: Model ID'si boş olamaz. Devam etmek için lütfen geçerli bir ID girin.", "Evaluations": "Değerlendirmeler", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API Anahtarı", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Örnek: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Örnek: ALL", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "{{URL}} terminal sunucusuna bağlanılamadı", "Failed to copy link": "Bağlantı kopyalanamadı", "Failed to create API Key.": "API Anahtarı oluşturulamadı.", + "Failed to delete calendar": "", "Failed to delete note": "Not silinemedi", "Failed to download image": "Görsel indirilemedi", "Failed to extract content from the file: {{error}}": "Dosyadan içerik çıkarılamadı: {{error}}", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Eşzamanlı arama sorgularını sınırla. 0 = sınırsız (varsayılan). Sıralı yürütme için 1 olarak ayarlayın (Brave ücretsiz katman gibi katı oran sınırlarına sahip API'ler için önerilir).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Dinleniyor...", "Live": "", "Llama.cpp": "", @@ -1206,6 +1229,7 @@ "local": "", "Local": "Yerel", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "Kayıp", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "'{{modelName}}' başarıyla indirildi.", "Model '{{modelTag}}' is already in queue for downloading.": "'{{modelTag}}' zaten indirme sırasında.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Model {{modelName}} görüntü yeteneğine sahip değil", "Model {{name}} is now {{status}}": "{{name}} modeli artık {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "Model {{name}} artık görünür", "Model accepts file inputs": "Model dosya girdilerini kabul eder", "Model accepts image inputs": "Model görüntü girdilerini kabul eder", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Model kod çalıştırabilir ve hesaplamalar yapabilir", "Model can generate images based on text prompts": "Model, metin promptlarına göre görsel oluşturabilir", "Model can search the web for information": "Model bilgileri aramak için web'de arama yapabilir", @@ -1313,6 +1339,7 @@ "Models Sharing": "Model Paylaşımı", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API Anahtarı", + "Month": "", "Monthly": "", "More": "Daha Fazla", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "Yeni Sohbet", + "New Event": "", "New File": "", "New Folder": "Yeni Klasör", "New Function": "Yeni Fonksiyon", @@ -1500,6 +1528,7 @@ "Password": "Parola", "Passwords do not match.": "Parolalar eşleşmiyor.", "Paste Large Text as File": "Büyük Metni Dosya Olarak Yapıştır", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF belgesi (.pdf)", "PDF Extract Images (OCR)": "PDF Görüntülerini Çıkart (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Kaydet", "Record voice": "Ses kaydı yap", "Redirecting you to Open WebUI Community": "OpenWebUI Topluluğuna yönlendiriliyorsunuz", @@ -1630,6 +1660,7 @@ "Relevance": "İlgili", "Relevance Threshold": "İlgi Eşiği", "Remember Dismissal": "", + "Reminder": "", "Remove": "Kaldır", "Remove {{MODELID}} from list.": "{{MODELID}} modelini listeden kaldır.", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Yeniden Sıralama Modeli", "Reset": "Sıfırla", @@ -1875,7 +1907,11 @@ "Start a new conversation": "Yeni bir konuşma başlat", "Start of the channel": "Kanalın başlangıcı", "Start Tag": "Başlangıç Etiketi", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Kernel başlatılıyor...", + "Starting now": "", "State": "", "Status": "Durum", "Status cleared successfully": "Durum başarıyla temizlendi", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "{{NAME}} ve tüm içeriği silinecek.", "This will delete all models including custom models": "Bu, özel modeller dahil olmak üzere tüm modelleri silecek", "This will delete all models including custom models and cannot be undone.": "Bu, özel modeller dahil olmak üzere tüm modelleri silecek ve geri alınamaz.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Bu, bilgi tabanını sıfırlayacak ve tüm dosyaları senkronize edecek. Devam etmek istiyor musunuz?", "Thorough explanation": "Kapsamlı açıklama", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Başlık boş bir dize olamaz.", "Title Generation": "Başlık Oluşturma", "Title Generation Prompt": "Başlık Oluşturma Prompt'u", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "İndirilebilir mevcut model adlarına erişmek için,", "To access the GGUF models available for downloading,": "İndirilebilir mevcut GGUF modellerine erişmek için,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} sonra modeli bellekten boşaltır", "Unlock mysteries": "", "Unpin": "Sabitlemeyi Kaldır", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI, \"{{url}}/api/chat\" adresine istek yapacak", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI, \"{{url}}/chat/completions\" adresine istek yapacak", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Ne yapmaya çalışıyorsunuz?", "What are you working on?": "Üzerinde çalıştığınız nedir?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "Yenilikler:", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Etkinleştirildiğinde, model her sohbet mesajına gerçek zamanlı olarak yanıt verecek ve kullanıcı bir mesaj gönderdiği anda bir yanıt üretecektir. Bu mod canlı sohbet uygulamaları için yararlıdır, ancak daha yavaş donanımlarda performansı etkileyebilir.", "wherever you are": "nerede olursanız olun", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/ug-CN/translation.json b/src/lib/i18n/locales/ug-CN/translation.json index b7fee9fb65..ba0727be45 100644 --- a/src/lib/i18n/locales/ug-CN/translation.json +++ b/src/lib/i18n/locales/ug-CN/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} نىڭ سۆھبەتلىرى", "{{webUIName}} Backend Required": "{{webUIName}} ئارقا سۇپا زۆرۈر", "*Prompt node ID(s) are required for image generation": "رەسىم ھاسىل قىلىش ئۈچۈن تۈرتكە نۇسخا ئۇچۇر ID(لىرى) زۆرۈر", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "يېڭى نەشرى (v{{LATEST_VERSION}}) مەۋجۇت.", @@ -47,6 +52,7 @@ "Access Control": "زىيارەت باشقۇرۇش", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "بارلىق ئىشلەتكۈچىلەر كىرەلەيدىغان", "Account": "ھېسابات", "Account Activation Pending": "ھېسابات ئاكتىپلىنىشى كۈتۈلمەكتە", @@ -72,9 +78,11 @@ "Add content here": "مەزمۇننى بۇ يەرگە قوشۇڭ", "Add Custom Parameter": "ئۆزلۈك پارامېتىر قوشۇش", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "ھۆججەتلەر قوشۇش", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "ئەسلەتمە قوشۇش", @@ -110,6 +118,7 @@ "AI": "", "All": "ھەممىسى", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "بارلىق مودېللار مۇۋەپپەقىيەتلىك ئۆچۈرۈلدى", @@ -198,6 +207,7 @@ "Ask a question": "سؤئال سوراڭ", "Assistant": "ياردەمچى", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "تور يۈكلىگۈچتىن ئۆتۈپ كېتىش", "Cache Base Model List": "", "Calendar": "كالىندار", + "Calendar deleted": "", + "Calendars": "", "Call": "چاقىرىش", "Call feature is not supported when using Web STT engine": "تور STT ماتورى ئىشلىتىلگەندە چاقىرىش ئىقتىدارى قوللىنىلمايدۇ", "Camera": "كامېرا", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "OpenAPI ماس كېلىدىغان سىرتقى قورال مۇلازىمېتىرلىرىغا باغلىنىڭ.", "Connected ({{type}})": "", "Connection failed": "ئۇلىنىش مەغلۇپ بولدى", + "Connection lost. Reconnecting...": "", "Connection successful": "ئۇلىنىش مۇۋەپپەقىيەتلىك", "Connection Type": "ئۇلىنىش تىپى", "Connections": "ئۇلىنىشلەر", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "ئۇلانما كۆچۈرۈش", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "چاپلاش تاختىسىغا كۆچۈرۈش", @@ -519,8 +533,11 @@ "Delete All Chats": "بارلىق سۆھبەتلەرنى ئۆچۈرۈش", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "سۆھبەت ئۆچۈرۈش", "Delete chat?": "سۆھبەت ئۆچۈرەمسىز؟", + "Delete Event": "", "Delete File": "", "Delete folder?": "قىسقۇچ ئۆچۈرەمسىز؟", "Delete function?": "فۇنكسىيە ئۆچۈرەمسىز؟", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "باھالاشلار", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API ئاچقۇچى", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "مەسىلەن: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "مەسىلەن: ALL", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "ئۇلانما كۆچۈرۈش مەغلۇپ بولدى", "Failed to create API Key.": "API ئاچقۇچى قۇرۇش مەغلۇپ بولدى.", + "Failed to delete calendar": "", "Failed to delete note": "خاتىرە ئۆچۈرۈش مەغلۇپ بولدى", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "ئاڭلاۋاتىدۇ...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "", "Local": "يەرلىك", "Local Task Model": "يەرلىك ۋەزىپە مودېلى", + "Location": "", "Location access not allowed": "ئورۇن زىيارىتىغا ئىجازەت يوق", "Lost": "يوقاپ كەتتى", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "مودېل", "Model '{{modelName}}' has been successfully downloaded.": "مودېل '{{modelName}}' مۇۋەپپەقىيەتلىك چۈشۈرۈلدى.", "Model '{{modelTag}}' is already in queue for downloading.": "مودېل '{{modelTag}}' ئاللىقاچان چۈشۈرۈش قاتارىغا قوشۇلغان.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "مودېل {{modelName}} كۆرۈنۈش ئىقتىدارى يوق", "Model {{name}} is now {{status}}": "مودېل {{name}} ھازىر {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "مودېل {{name}} ھازىر كۆرۈنىدۇ", "Model accepts file inputs": "مودېل ھۆججەت كىرگۈزۈشنى قوبۇل قىلىدۇ", "Model accepts image inputs": "مودېل رەسىم كىرگۈزۈشنى قوبۇل قىلىدۇ", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "مودېل كود ئىجرا قىلىپ ھېسابلاشقا قادىر", "Model can generate images based on text prompts": "مودېل تېكست تۈرتكە ئارقىلىق رەسىم ھاسىل قىلالايدۇ", "Model can search the web for information": "مودېل توردا ئۇچۇر ئىزدەيدۇ", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek ئىزدەش API ئاچقۇچى", + "Month": "", "Monthly": "", "More": "تېخىمۇ كۆپ", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "يېڭى سۆھبەت", + "New Event": "", "New File": "", "New Folder": "يېڭى قىسقۇچ", "New Function": "يېڭى فۇنكسىيە", @@ -1500,6 +1528,7 @@ "Password": "پارول", "Passwords do not match.": "", "Paste Large Text as File": "چوڭ تېكستنى ھۆججەت قىلىپ چاپلا", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF ھۆججىتى (.pdf)", "PDF Extract Images (OCR)": "PDF رەسىم چىقىرىش (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "چۈشەندۈرۈش كۈچى", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "خاتىرىلەش", "Record voice": "ئاۋاز خاتىرىلەش", "Redirecting you to Open WebUI Community": "Open WebUI جەمئىيىتىگە يوللاندى", @@ -1630,6 +1660,7 @@ "Relevance": "مۇناسىۋەتلىكلىك", "Relevance Threshold": "مۇناسىۋەتلىكلىك چەك قىممىتى", "Remember Dismissal": "", + "Reminder": "", "Remove": "چىقىرىۋېتىش", "Remove {{MODELID}} from list.": "تىزىمدىن {{MODELID}} چىقىرىۋېتىش.", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "قايتا تەرتىپلەش ماتورى", "Reranking Model": "قايتا تەرتىپلەش مودېلى", "Reset": "قايتا تەڭشەش", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "قانالنىڭ باشلانغىنى", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "{{NAME}} ۋە بارلىق مەزمۇنى ئۆچۈرۈلىدۇ.", "This will delete all models including custom models": "بۇ بارلىق مودېللارنى ئۆچۈرۈدۇ (ئۆزلۈك مودېللارنىمۇ ئۆز ئىچىگە ئالىدۇ)", "This will delete all models including custom models and cannot be undone.": "بۇ بارلىق مودېللارنى ئۆچۈرۈدۇ (ئۆزلۈك مودېللارنىمۇ ئۆز ئىچىگە ئالىدۇ) ۋە ئەسلىگە كەلتۈرگىلى بولمايدۇ.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "بىلىم ئاساسى قايتا تەڭشىلىپ بارلىق ھۆججەتلەر ماس-قەدەملىنىدۇ. داۋاملاشامسىز؟", "Thorough explanation": "تەپسىلىي چۈشەندۈرۈش", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "تېما بوش بولسا بولمايدۇ.", "Title Generation": "تېما ھاسىل قىلىش", "Title Generation Prompt": "تېما ھاسىل قىلىش تۈرتكەسى", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "چۈشۈرۈشكە بولىدىغان مودېل ئاتىنى كۆرۈش ئۈچۈن،", "To access the GGUF models available for downloading,": "چۈشۈرۈشكە بولىدىغان GGUF مودېللارنى كۆرۈش ئۈچۈن،", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} چىقىرىلىدۇ", "Unlock mysteries": "سىرلارنى ئاچ", "Unpin": "مۇقىملانمىغان قىلىش", + "Unpin from Sidebar": "", "Unravel secrets": "سىرنى ئاچ", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI \"{{url}}\" غا تەلەپ يوللايدۇ", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI \"{{url}}/api/chat\" غا تەلەپ يوللايدۇ", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" غا تەلەپ يوللايدۇ", + "Week": "", "Weekly": "", "What are you trying to achieve?": "نېمىگە ئېرىشمىكچىسىز؟", "What are you working on?": "نېمە ئىش قىلىۋاتىسىز؟", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "يېڭىلىق", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "قوزغىتىلسا، مودېل ھەر بىر سۆھبەت ئۇچۇرىغا ۋاقىتدا ئىنكاس قايتۇرىدۇ. بۇ ھالىتى تۇرۇشلۇق سۆھبەت ئۈچۈن پايدىلىق، بىراق ئاستا ئۈسكۈنىدە ئۈنۈمگە تەسىر قىلىدۇ.", "wherever you are": "قايسى يەردە بولسىڭىزمۇ", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "چىقىرىشنى بەتلەندۈرۈش ئۈچۈن ئىشلىتىلدۇ. ھەربىر بەت گىزىكچىلەر بىلەن ئايرىلىدۇ. كۆڭۈلدىكىچە چەكلەنگەن.", diff --git a/src/lib/i18n/locales/uk-UA/translation.json b/src/lib/i18n/locales/uk-UA/translation.json index 67ab638362..46de023a39 100644 --- a/src/lib/i18n/locales/uk-UA/translation.json +++ b/src/lib/i18n/locales/uk-UA/translation.json @@ -35,8 +35,13 @@ "{{user}}'s Chats": "Чати {{user}}а", "{{webUIName}} Backend Required": "Необхідно підключення бекенду {{webUIName}}", "*Prompt node ID(s) are required for image generation": "*Для генерації зображення потрібно вказати ідентифікатор(и) вузла(ів)", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Нова версія (v{{LATEST_VERSION}}) зараз доступна.", @@ -49,6 +54,7 @@ "Access Control": "Контроль доступу", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Доступно всім користувачам", "Account": "Обліковий запис", "Account Activation Pending": "Очікування активації облікового запису", @@ -74,9 +80,11 @@ "Add content here": "Додайте вміст сюди", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Додати файли", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Додати пам'ять", @@ -112,6 +120,7 @@ "AI": "", "All": "Усі", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Усі моделі видалені успішно", @@ -200,6 +209,7 @@ "Ask a question": "Задати питання", "Assistant": "Асистент", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -274,6 +284,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Календар", + "Calendar deleted": "", + "Calendars": "", "Call": "Виклик", "Call feature is not supported when using Web STT engine": "Функція виклику не підтримується при використанні Web STT (розпізнавання мовлення) рушія", "Camera": "Камера", @@ -410,6 +422,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Підключіться до своїх власних зовнішніх серверів інструментів, сумісних з OpenAPI.", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "З'єднання", @@ -441,6 +454,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Копіювати посилання", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Копіювати в буфер обміну", @@ -521,8 +535,11 @@ "Delete All Chats": "Видалити усі чати", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Видалити чат", "Delete chat?": "Видалити чат?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Видалити папку?", "Delete function?": "Видалити функцію?", @@ -829,6 +846,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Оцінювання", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API ключ", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Приклад: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Приклад: УСІ", @@ -877,6 +898,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Не вдалося створити API ключ.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1198,6 +1220,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Слухаю...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1208,6 +1231,7 @@ "local": "", "Local": "Локальний", "Local Task Model": "", + "Location": "", "Location access not allowed": "Доступ до місцезнаходження не дозволено", "Lost": "Втрачене", "Low": "", @@ -1275,6 +1299,7 @@ "Model": "Модель", "Model '{{modelName}}' has been successfully downloaded.": "Модель '{{modelName}}' успішно завантажено.", "Model '{{modelTag}}' is already in queue for downloading.": "Модель '{{modelTag}}' вже знаходиться в черзі на завантаження.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Модель {{modelName}} не здатна бачити", "Model {{name}} is now {{status}}": "Модель {{name}} тепер має {{status}}", @@ -1282,6 +1307,7 @@ "Model {{name}} is now visible": "Модель {{name}} тепер видима", "Model accepts file inputs": "", "Model accepts image inputs": "Модель приймає зображеня", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1315,6 +1341,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "API ключ для пошуку Mojeek", + "Month": "", "Monthly": "", "More": "Більше", "More Concise": "", @@ -1333,6 +1360,7 @@ "New Automation": "", "New Button": "", "New Chat": "Новий чат", + "New Event": "", "New File": "", "New Folder": "Нова папка", "New Function": "", @@ -1502,6 +1530,7 @@ "Password": "Пароль", "Passwords do not match.": "", "Paste Large Text as File": "Вставити великий текст як файл", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF документ (.pdf)", "PDF Extract Images (OCR)": "Розпізнавання зображень з PDF (OCR)", @@ -1609,6 +1638,7 @@ "Reasoning Effort": "Зусилля на міркування", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Записати голос", "Redirecting you to Open WebUI Community": "Перенаправляємо вас до спільноти OpenWebUI", @@ -1632,6 +1662,7 @@ "Relevance": "Актуальність", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Видалити", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1650,6 +1681,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Модель переранжування", "Reset": "Скидання", @@ -1879,7 +1911,13 @@ "Start a new conversation": "", "Start of the channel": "Початок каналу", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1992,6 +2030,7 @@ "This will delete {{NAME}} and all its contents.": "Це видалить {{NAME}} та усі його вмісти.", "This will delete all models including custom models": "Це видалить усі моделі, включаючи користувацькі моделі", "This will delete all models including custom models and cannot be undone.": "Це видалить усі моделі, включаючи користувацькі моделі, і не може бути скасовано.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Це скине базу знань і синхронізує усі файли. Ви бажаєте продовжити?", "Thorough explanation": "Детальне пояснення", "Thought": "", @@ -2011,6 +2050,7 @@ "Title cannot be an empty string.": "Заголовок не може бути порожнім рядком.", "Title Generation": "Генерація заголовка", "Title Generation Prompt": "Промт для генерування заголовків", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Щоб отримати доступ до назв доступних для завантаження моделей,", "To access the GGUF models available for downloading,": "Щоб отримати доступ до моделей GGUF, які можна завантажити,,", @@ -2077,6 +2117,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Розкрийте таємниці", "Unpin": "Відчепити", + "Unpin from Sidebar": "", "Unravel secrets": "Розплутуйте секрети", "Unshare Chat": "", "Unsupported file type.": "", @@ -2181,6 +2222,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI надсилатиме запити до \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI надсилатиме запити до \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Чого ви прагнете досягти?", "What are you working on?": "Над чим ти працюєш?", @@ -2188,6 +2230,7 @@ "What is shared:": "", "What's New in": "Що нового в", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Коли активовано, модель буде відповідати на кожне повідомлення чату в режимі реального часу, генеруючи відповідь, як тільки користувач надішле повідомлення. Цей режим корисний для застосувань життєвих вітань чатів, але може позначитися на продуктивності на повільнішому апаратному забезпеченні.", "wherever you are": "де б ви не були", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/ur-PK/translation.json b/src/lib/i18n/locales/ur-PK/translation.json index 8ac674cc4b..967dd471db 100644 --- a/src/lib/i18n/locales/ur-PK/translation.json +++ b/src/lib/i18n/locales/ur-PK/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{ صارف }} کی بات چیت", "{{webUIName}} Backend Required": "{{webUIName}} بیک اینڈ درکار ہے", "*Prompt node ID(s) are required for image generation": "تصویر کی تخلیق کے لیے *پرومپٹ نوڈ آئی ڈی(ز) کی ضرورت ہے", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "نیا ورژن (v{{LATEST_VERSION}}) اب دستیاب ہے", @@ -47,6 +52,7 @@ "Access Control": "", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "", "Account": "اکاؤنٹ", "Account Activation Pending": "اکاؤنٹ فعال ہونے کا انتظار ہے", @@ -72,9 +78,11 @@ "Add content here": "یہاں مواد شامل کریں", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "فائلیں شامل کریں", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "میموری شامل کریں", @@ -110,6 +118,7 @@ "AI": "", "All": "", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "", @@ -198,6 +207,7 @@ "Ask a question": "سوال پوچھیں", "Assistant": "اسسٹنٹ", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", + "Calendars": "", "Call": "کال کریں", "Call feature is not supported when using Web STT engine": "کال کی خصوصیت ویب STT انجن استعمال کرتے وقت معاونت یافتہ نہیں ہے", "Camera": "کیمرہ", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "کنکشنز", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "لنک کاپی کریں", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "کلپ بورڈ پر کاپی کریں", @@ -519,8 +533,11 @@ "Delete All Chats": "تمام چیٹس حذف کریں", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "چیٹ حذف کریں", "Delete chat?": "چیٹ حذف کریں؟", + "Delete Event": "", "Delete File": "", "Delete folder?": "کیا فولڈر حذف کریں؟", "Delete function?": "حذف کریں؟", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "تشخیصات", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "", "Example: ALL": "", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "API کلید بنانے میں ناکام", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "سن رہے ہیں...", "Live": "", "Llama.cpp": "", @@ -1206,6 +1229,7 @@ "local": "", "Local": "", "Local Task Model": "", + "Location": "", "Location access not allowed": "", "Lost": "گم شدہ", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "ماڈل", "Model '{{modelName}}' has been successfully downloaded.": "ماڈل '{{modelName}}' کامیابی سے ڈاؤن لوڈ ہو گیا ہے", "Model '{{modelTag}}' is already in queue for downloading.": "ماڈل '{{modelTag}}' پہلے ہی ڈاؤن لوڈ کے لیے قطار میں ہے", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "ماڈل {{modelName}} بصری صلاحیت نہیں رکھتا", "Model {{name}} is now {{status}}": "ماڈل {{name}} اب {{status}} ہے", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "", "Model accepts file inputs": "", "Model accepts image inputs": "ماڈل تصویری ان پٹس قبول کرتا ہے", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "", + "Month": "", "Monthly": "", "More": "مزید", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "نئی بات چیت", + "New Event": "", "New File": "", "New Folder": "", "New Function": "", @@ -1500,6 +1528,7 @@ "Password": "پاس ورڈ", "Passwords do not match.": "", "Paste Large Text as File": "", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "پی ڈی ایف دستاویز (.pdf)", "PDF Extract Images (OCR)": "پی ڈی ایف سے تصاویر نکالیں (او سی آر)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "صوت ریکارڈ کریں", "Redirecting you to Open WebUI Community": "آپ کو اوپن ویب یو آئی کمیونٹی کی طرف ری ڈائریکٹ کیا جا رہا ہے", @@ -1630,6 +1660,7 @@ "Relevance": "موزونیت", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "ہٹا دیں", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "دوبارہ درجہ بندی کا ماڈل", "Reset": "ری سیٹ", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "چینل کی شروعات", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "یہ {{NAME}} اور اس کے تمام مواد کو حذف کر دے گا", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "یہ علمی بنیاد کو دوبارہ ترتیب دے گا اور تمام فائلز کو متوازن کرے گا کیا آپ جاری رکھنا چاہتے ہیں؟", "Thorough explanation": "مکمل وضاحت", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "عنوان خالی اسٹرنگ نہیں ہو سکتا", "Title Generation": "", "Title Generation Prompt": "سرخی بنانے کی ہدایت", + "Title is required": "", "TLS": "", "To access the available model names for downloading,": "ڈاؤن لوڈ کرنے کے لئے دستیاب ماڈل کے ناموں تک رسائی حاصل کرنے کے لئے،", "To access the GGUF models available for downloading,": "GGUF ماڈلز تک رسائی حاصل کرنے کے لئے جو ڈاؤنلوڈنگ کے لئے دستیاب ہیں،", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "ان پن کریں", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "", "WebUI will make requests to \"{{url}}/api/chat\"": "", "WebUI will make requests to \"{{url}}/chat/completions\"": "", + "Week": "", "Weekly": "", "What are you trying to achieve?": "", "What are you working on?": "", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "میں نیا کیا ہے", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "wherever you are": "", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json index 3ffd9ab2fa..fe4f5b1da1 100644 --- a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json +++ b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} нинг чатлари", "{{webUIName}} Backend Required": "{{webUIName}} Баcкенд талаб қилинади", "*Prompt node ID(s) are required for image generation": "*Расм яратиш учун тезкор тугун идентификаторлари талаб қилинади", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Энди янги версия (v{{LATEST_VERSION}}) мавжуд.", @@ -47,6 +52,7 @@ "Access Control": "Кириш назорати", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Барча фойдаланувчилар учун очиқ", "Account": "Ҳисоб", "Account Activation Pending": "Ҳисобни фаоллаштириш кутилмоқда", @@ -72,9 +78,11 @@ "Add content here": "Бу ерга таркиб қўшинг", "Add Custom Parameter": "Махсус параметр қўшинг", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Файлларни қўшиш", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Хотира қўшиш", @@ -110,6 +118,7 @@ "AI": "", "All": "Ҳаммаси", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Барча моделлар муваффақиятли ўчирилди", @@ -198,6 +207,7 @@ "Ask a question": "Савол беринг", "Assistant": "Ёрдамчи", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "Веб юклагични четлаб ўтиш", "Cache Base Model List": "", "Calendar": "Календар", + "Calendar deleted": "", + "Calendars": "", "Call": "Қўнғироқ қилинг", "Call feature is not supported when using Web STT engine": "Wеб СТТ механизмидан фойдаланилганда қўнғироқ функсияси қўллаб-қувватланмайди", "Camera": "Камера", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Ўзингизнинг OpenAIга мос келадиган ташқи асбоблар серверларига уланинг.", "Connected ({{type}})": "", "Connection failed": "Уланиш амалга ошмади", + "Connection lost. Reconnecting...": "", "Connection successful": "Уланиш муваффақиятли", "Connection Type": "Уланиш тури", "Connections": "Уланишлар", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Ҳаволани нусхалаш", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Буферга нусхалаш", @@ -519,8 +533,11 @@ "Delete All Chats": "Барча суҳбатларни ўчириш", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Чатни ўчириш", "Delete chat?": "Чат ўчирилсинми?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Жилд ўчирилсинми?", "Delete function?": "Функция ўчирилсинми?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Баҳолар", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa АПИ калити", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Мисол: (&(обжеcтCласс=инетОргПерсон)(уид=%с))", "Example: ALL": "Мисол: АЛЛ", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Ҳаволани нусхалаб бўлмади", "Failed to create API Key.": "АПИ калитини яратиб бўлмади.", + "Failed to delete calendar": "", "Failed to delete note": "Қайдни ўчириб бўлмади", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Тингланмоқда...", "Live": "", "Llama.cpp": "Ллама.cпп", @@ -1206,6 +1229,7 @@ "local": "", "Local": "Маҳаллий", "Local Task Model": "Маҳаллий вазифа модели", + "Location": "", "Location access not allowed": "Жойлашувга рухсат берилмаган", "Lost": "Йўқотилган", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "Модел", "Model '{{modelName}}' has been successfully downloaded.": "“{{modelName}}” модели юклаб олинди.", "Model '{{modelTag}}' is already in queue for downloading.": "“{{modelTag}}” модели аллақачон юклаб олиш учун навбатда турибди.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "{{modelName}} модели кўриш қобилиятига эга эмас", "Model {{name}} is now {{status}}": "{{name}} модели энди {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "{{name}} модели энди кўринади", "Model accepts file inputs": "Модел файл киришларини қабул қилади", "Model accepts image inputs": "Модел расм киритишни қабул қилади", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Модел кодни бажариши ва ҳисоб-китобларни амалга ошириши мумкин", "Model can generate images based on text prompts": "Модел матн таклифлари асосида тасвирларни яратиши мумкин", "Model can search the web for information": "Модел маълумот учун Интернетда қидириши мумкин", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Можеэк қидирув АПИ калити", + "Month": "", "Monthly": "", "More": "Кўпроқ", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "Янги чат", + "New Event": "", "New File": "", "New Folder": "Янги жилд", "New Function": "Янги функсия", @@ -1500,6 +1528,7 @@ "Password": "Парол", "Passwords do not match.": "", "Paste Large Text as File": "Катта матнни файл сифатида жойлаштиринг", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "ПДФ ҳужжат (.pdf)", "PDF Extract Images (OCR)": "ПДФ экстракти расмлари (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Мулоҳаза юритиш ҳаракатлари", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Ёзиб олиш", "Record voice": "Овозни ёзиб олинг", "Redirecting you to Open WebUI Community": "Сизни Опен WебУИ ҳамжамиятига йўналтирмоқда", @@ -1630,6 +1660,7 @@ "Relevance": "Мувофиқлик", "Relevance Threshold": "Мувофиқлик чегараси", "Remember Dismissal": "", + "Reminder": "", "Remove": "Ўчириш", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "Двигателни қайта тартиблаш", "Reranking Model": "Қайта тартиблаш модели", "Reset": "Қайта тиклаш", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Канал боши", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Бу <стронг>{{NAME}} ва <стронг>барча мазмунини ўчириб ташлайди.", "This will delete all models including custom models": "Бу барча моделларни, шу жумладан махсус моделларни ўчириб ташлайди", "This will delete all models including custom models and cannot be undone.": "Бу барча моделларни, жумладан, махсус моделларни ҳам ўчириб ташлайди ва уларни ортга қайтариб бўлмайди.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Бу билимлар базасини қайта тиклайди ва барча файлларни синхронлаштиради. Давом этишни хоҳлайсизми?", "Thorough explanation": "Тўлиқ тушунтириш", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Сарлавҳа бўш қатор бўлиши мумкин эмас.", "Title Generation": "Сарлавҳа яратиш", "Title Generation Prompt": "Сарлавҳа яратиш таклифи", + "Title is required": "", "TLS": "ТЛС", "To access the available model names for downloading,": "Юклаб олиш учун мавжуд модел номларига кириш учун,", "To access the GGUF models available for downloading,": "Юклаб олиш мумкин бўлган ГГУФ моделларига кириш учун,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} юклайди", "Unlock mysteries": "Сирларни очинг", "Unpin": "Ечиш", + "Unpin from Sidebar": "", "Unravel secrets": "Сирларни очинг", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI “{{url}}” манзилига сўров юборади", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI “{{url}}/api/chat” манзилига сўров юборади", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" манзилига сўров юборади", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Нимага эришмоқчисиз?", "What are you working on?": "Нима устида ишлаяпсиз?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Ёқилганда, модел реал вақт режимида ҳар бир чат хабарига жавоб беради ва фойдаланувчи хабар юбориши биланоқ жавоб ҳосил қилади. Ушбу режим жонли чат иловалари учун фойдалидир, лекин секинроқ ускунанинг ишлашига таъсир қилиши мумкин.", "wherever you are": "қаерда бўлсангиз ҳам", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Чиқишни саҳифалаш керакми. Ҳар бир саҳифа горизонтал қоида ва саҳифа рақами билан ажратилади. Бирламчи параметрлар Фалсе.", diff --git a/src/lib/i18n/locales/uz-Latn-Uz/translation.json b/src/lib/i18n/locales/uz-Latn-Uz/translation.json index 06bd7cf1fa..2ffada0eab 100644 --- a/src/lib/i18n/locales/uz-Latn-Uz/translation.json +++ b/src/lib/i18n/locales/uz-Latn-Uz/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} ning chatlari", "{{webUIName}} Backend Required": "{{webUIName}} Backend talab qilinadi", "*Prompt node ID(s) are required for image generation": "*Rasm yaratish uchun tezkor tugun identifikatorlari talab qilinadi", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Endi yangi versiya (v{{LATEST_VERSION}}) mavjud.", @@ -47,6 +52,7 @@ "Access Control": "Kirish nazorati", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Barcha foydalanuvchilar uchun ochiq", "Account": "Hisob", "Account Activation Pending": "Hisobni faollashtirish kutilmoqda", @@ -72,9 +78,11 @@ "Add content here": "Bu yerga tarkib qo'shing", "Add Custom Parameter": "Maxsus parametr qo'shing", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Fayllarni qo'shish", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Xotira qo'shish", @@ -110,6 +118,7 @@ "AI": "", "All": "Hammasi", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Barcha modellar muvaffaqiyatli o'chirildi", @@ -198,6 +207,7 @@ "Ask a question": "Savol bering", "Assistant": "Yordamchi", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -272,6 +282,8 @@ "Bypass Web Loader": "Veb yuklagichni chetlab o'tish", "Cache Base Model List": "", "Calendar": "Kalendar", + "Calendar deleted": "", + "Calendars": "", "Call": "Qo'ng'iroq qiling", "Call feature is not supported when using Web STT engine": "Web STT mexanizmidan foydalanilganda qo'ng'iroq funksiyasi qo'llab-quvvatlanmaydi", "Camera": "Kamera", @@ -408,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "O'zingizning OpenAPI-ga mos keladigan tashqi asboblar serverlariga ulaning.", "Connected ({{type}})": "", "Connection failed": "Ulanish amalga oshmadi", + "Connection lost. Reconnecting...": "", "Connection successful": "Ulanish muvaffaqiyatli", "Connection Type": "Ulanish turi", "Connections": "Ulanishlar", @@ -439,6 +452,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Havolani nusxalash", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Buferga nusxalash", @@ -519,8 +533,11 @@ "Delete All Chats": "Barcha suhbatlarni o'chirish", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Chatni oʻchirish", "Delete chat?": "Chat oʻchirilsinmi?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Jild oʻchirilsinmi?", "Delete function?": "Funktsiya o'chirilsinmi?", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Baholar", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API kaliti", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Misol: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Misol: ALL", @@ -875,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Havolani nusxalab bo‘lmadi", "Failed to create API Key.": "API kalitini yaratib bo‘lmadi.", + "Failed to delete calendar": "", "Failed to delete note": "Qaydni o‘chirib bo‘lmadi", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1196,6 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Tinglanmoqda...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1229,7 @@ "local": "", "Local": "Mahalliy", "Local Task Model": "Mahalliy vazifa modeli", + "Location": "", "Location access not allowed": "Joylashuvga ruxsat berilmagan", "Lost": "Yo'qotilgan", "Low": "", @@ -1273,6 +1297,7 @@ "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "“{{modelName}}” modeli yuklab olindi.", "Model '{{modelTag}}' is already in queue for downloading.": "“{{modelTag}}” modeli allaqachon yuklab olish uchun navbatda turibdi.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "{{modelName}} modeli ko'rish qobiliyatiga ega emas", "Model {{name}} is now {{status}}": "{{name}} modeli endi {{status}}", @@ -1280,6 +1305,7 @@ "Model {{name}} is now visible": "{{name}} modeli endi koʻrinadi", "Model accepts file inputs": "Model fayl kirishlarini qabul qiladi", "Model accepts image inputs": "Model rasm kiritishni qabul qiladi", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "Model kodni bajarishi va hisob-kitoblarni amalga oshirishi mumkin", "Model can generate images based on text prompts": "Model matn takliflari asosida tasvirlarni yaratishi mumkin", "Model can search the web for information": "Model ma'lumot uchun Internetda qidirishi mumkin", @@ -1313,6 +1339,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Mojeek qidiruv API kaliti", + "Month": "", "Monthly": "", "More": "Ko'proq", "More Concise": "", @@ -1331,6 +1358,7 @@ "New Automation": "", "New Button": "", "New Chat": "Yangi chat", + "New Event": "", "New File": "", "New Folder": "Yangi jild", "New Function": "Yangi funksiya", @@ -1500,6 +1528,7 @@ "Password": "Parol", "Passwords do not match.": "", "Paste Large Text as File": "Katta matnni fayl sifatida joylashtiring", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "PDF hujjat (.pdf)", "PDF Extract Images (OCR)": "PDF ekstrakti rasmlari (OCR)", @@ -1607,6 +1636,7 @@ "Reasoning Effort": "Mulohaza yuritish harakatlari", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Yozib olish", "Record voice": "Ovozni yozib oling", "Redirecting you to Open WebUI Community": "Sizni Open WebUI hamjamiyatiga yoʻnaltirmoqda", @@ -1630,6 +1660,7 @@ "Relevance": "Muvofiqlik", "Relevance Threshold": "Muvofiqlik chegarasi", "Remember Dismissal": "", + "Reminder": "", "Remove": "O'chirish", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1648,6 +1679,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "Dvigatelni qayta tartiblash", "Reranking Model": "Qayta tartiblash modeli", "Reset": "Qayta tiklash", @@ -1875,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Kanal boshlanishi", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1988,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Bu {{NAME}} va barcha mazmunini o‘chirib tashlaydi.", "This will delete all models including custom models": "Bu barcha modellarni, shu jumladan maxsus modellarni o'chirib tashlaydi", "This will delete all models including custom models and cannot be undone.": "Bu barcha modellarni, jumladan, maxsus modellarni ham o‘chirib tashlaydi va ularni ortga qaytarib bo‘lmaydi.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Bu bilimlar bazasini qayta tiklaydi va barcha fayllarni sinxronlashtiradi. Davom etishni xohlaysizmi?", "Thorough explanation": "To'liq tushuntirish", "Thought": "", @@ -2007,6 +2044,7 @@ "Title cannot be an empty string.": "Sarlavha bo'sh qator bo'lishi mumkin emas.", "Title Generation": "Sarlavha yaratish", "Title Generation Prompt": "Sarlavha yaratish taklifi", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Yuklab olish uchun mavjud model nomlariga kirish uchun,", "To access the GGUF models available for downloading,": "Yuklab olish mumkin bo'lgan GGUF modellariga kirish uchun,", @@ -2073,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} yuklaydi", "Unlock mysteries": "Sirlarni oching", "Unpin": "Yechish", + "Unpin from Sidebar": "", "Unravel secrets": "Sirlarni oching", "Unshare Chat": "", "Unsupported file type.": "", @@ -2177,6 +2216,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI “{{url}}” manziliga so‘rov yuboradi", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI “{{url}}/api/chat” manziliga so‘rov yuboradi", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" manziliga so'rov yuboradi", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Nimaga erishmoqchisiz?", "What are you working on?": "Nima ustida ishlayapsiz?", @@ -2184,6 +2224,7 @@ "What is shared:": "", "What's New in": "", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Yoqilganda, model real vaqt rejimida har bir chat xabariga javob beradi va foydalanuvchi xabar yuborishi bilanoq javob hosil qiladi. Ushbu rejim jonli chat ilovalari uchun foydalidir, lekin sekinroq uskunaning ishlashiga ta'sir qilishi mumkin.", "wherever you are": "qayerda bo'lsangiz ham", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Chiqishni sahifalash kerakmi. Har bir sahifa gorizontal qoida va sahifa raqami bilan ajratiladi. Birlamchi parametrlar False.", diff --git a/src/lib/i18n/locales/vi-VN/translation.json b/src/lib/i18n/locales/vi-VN/translation.json index 604dac83f6..6810eb909a 100644 --- a/src/lib/i18n/locales/vi-VN/translation.json +++ b/src/lib/i18n/locales/vi-VN/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "Các cuộc trò chuyện của {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Yêu cầu Backend", "*Prompt node ID(s) are required for image generation": "*ID nút Prompt là bắt buộc để tạo ảnh", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Một phiên bản mới (v{{LATEST_VERSION}}) đã có sẵn.", @@ -46,6 +51,7 @@ "Access Control": "Kiểm soát truy cập", "Access Grants": "", "Access List": "", + "Access updated": "", "Accessible to all users": "Truy cập được bởi tất cả người dùng", "Account": "Tài khoản", "Account Activation Pending": "Tài khoản đang chờ kích hoạt", @@ -71,9 +77,11 @@ "Add content here": "Thêm nội dung tại đây", "Add Custom Parameter": "", "Add Custom Prompt": "", + "Add description": "", "Add Details": "", "Add Files": "Thêm tệp", "Add Image": "", + "Add location": "", "Add Member": "", "Add Members": "", "Add Memory": "Thêm bộ nhớ", @@ -109,6 +117,7 @@ "AI": "", "All": "Tất cả", "All chats have been unarchived.": "", + "All day": "", "All models are now hidden": "", "All models are now visible": "", "All models deleted successfully": "Tất cả các mô hình đã được xóa thành công", @@ -197,6 +206,7 @@ "Ask a question": "Đặt câu hỏi", "Assistant": "Trợ lý", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -271,6 +281,8 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Lịch", + "Calendar deleted": "", + "Calendars": "", "Call": "Gọi", "Call feature is not supported when using Web STT engine": "Tính năng gọi điện không được hỗ trợ khi sử dụng công cụ Web STT", "Camera": "Máy ảnh", @@ -407,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Kết nối với các máy chủ công cụ bên ngoài tương thích OpenAPI của riêng bạn.", "Connected ({{type}})": "", "Connection failed": "Kết nối thất bại", + "Connection lost. Reconnecting...": "", "Connection successful": "Kết nối thành công", "Connection Type": "", "Connections": "Kết nối", @@ -438,6 +451,7 @@ "Copy Last Response": "", "Copy link": "", "Copy Link": "Sao chép link", + "Copy Path": "", "Copy Prompt": "", "Copy Share Link": "", "Copy to clipboard": "Sao chép vào clipboard", @@ -518,8 +532,11 @@ "Delete All Chats": "Xóa mọi cuộc Chat", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Xóa chat", "Delete chat?": "Xóa chat?", + "Delete Event": "", "Delete File": "", "Delete folder?": "Xóa thư mục?", "Delete function?": "Xóa function?", @@ -826,6 +843,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", "Evaluations": "Đánh giá", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Khóa API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Ví dụ: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Ví dụ: TẤT CẢ", @@ -874,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Lỗi khởi tạo API Key", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1195,6 +1217,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", "List": "", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "Đang nghe...", "Live": "", "Llama.cpp": "Llama.cpp", @@ -1205,6 +1228,7 @@ "local": "", "Local": "Cục bộ", "Local Task Model": "", + "Location": "", "Location access not allowed": "Không cho phép truy cập vị trí", "Lost": "Thua", "Low": "", @@ -1272,6 +1296,7 @@ "Model": "Mô hình", "Model '{{modelName}}' has been successfully downloaded.": "Mô hình '{{modelName}}' đã được tải xuống thành công.", "Model '{{modelTag}}' is already in queue for downloading.": "Mô hình '{{modelTag}}' đã có trong hàng đợi để tải xuống.", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "", "Model {{modelName}} is not vision capable": "Model {{modelName}} không có khả năng nhìn", "Model {{name}} is now {{status}}": "Model {{name}} bây giờ là {{status}}", @@ -1279,6 +1304,7 @@ "Model {{name}} is now visible": "Mô hình {{name}} hiện có thể nhìn thấy", "Model accepts file inputs": "", "Model accepts image inputs": "Mô hình chấp nhận đầu vào hình ảnh", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "", "Model can generate images based on text prompts": "", "Model can search the web for information": "", @@ -1312,6 +1338,7 @@ "Models Sharing": "", "Mojeek": "", "Mojeek Search API Key": "Khóa API Mojeek Search", + "Month": "", "Monthly": "", "More": "Thêm", "More Concise": "", @@ -1330,6 +1357,7 @@ "New Automation": "", "New Button": "", "New Chat": "Tạo chat mới", + "New Event": "", "New File": "", "New Folder": "Thư mục Mới", "New Function": "", @@ -1499,6 +1527,7 @@ "Password": "Mật khẩu", "Passwords do not match.": "", "Paste Large Text as File": "Dán Văn bản Lớn dưới dạng Tệp", + "Path copied": "", "Paused": "", "PDF document (.pdf)": "Tập tin PDF (.pdf)", "PDF Extract Images (OCR)": "Trích xuất ảnh từ PDF (OCR)", @@ -1606,6 +1635,7 @@ "Reasoning Effort": "Nỗ lực Suy luận", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Ghi âm", "Redirecting you to Open WebUI Community": "Đang chuyển hướng bạn đến Cộng đồng OpenWebUI", @@ -1629,6 +1659,7 @@ "Relevance": "Mức độ liên quan", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Xóa", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1647,6 +1678,7 @@ "Reply to thread...": "", "Replying to {{NAME}}": "", "required": "", + "Reranking Batch Size": "", "Reranking Engine": "", "Reranking Model": "Reranking Model", "Reset": "Xóa toàn bộ", @@ -1873,7 +1905,10 @@ "Start a new conversation": "", "Start of the channel": "Đầu kênh", "Start Tag": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -1986,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "Hành động này sẽ xóa {{NAME}}tất cả nội dung của nó.", "This will delete all models including custom models": "Hành động này sẽ xóa tất cả các mô hình bao gồm cả các mô hình tùy chỉnh", "This will delete all models including custom models and cannot be undone.": "Hành động này sẽ xóa tất cả các mô hình bao gồm cả các mô hình tùy chỉnh và không thể hoàn tác.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Hành động này sẽ đặt lại cơ sở kiến thức và đồng bộ hóa tất cả các tệp. Bạn có muốn tiếp tục không?", "Thorough explanation": "Giải thích kỹ lưỡng", "Thought": "", @@ -2005,6 +2041,7 @@ "Title cannot be an empty string.": "Tiêu đề không được phép bỏ trống", "Title Generation": "Tạo Tiêu đề", "Title Generation Prompt": "Prompt tạo tiêu đề", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "Để truy cập tên các mô hình có sẵn để tải xuống,", "To access the GGUF models available for downloading,": "Để truy cập các mô hình GGUF có sẵn để tải xuống,", @@ -2071,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Mở khóa những bí ẩn", "Unpin": "Bỏ ghim", + "Unpin from Sidebar": "", "Unravel secrets": "Làm sáng tỏ những bí mật", "Unshare Chat": "", "Unsupported file type.": "", @@ -2175,6 +2213,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI sẽ thực hiện yêu cầu đến \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI sẽ thực hiện yêu cầu đến \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI sẽ thực hiện yêu cầu đến \"{{url}}/chat/completions\"", + "Week": "", "Weekly": "", "What are you trying to achieve?": "Bạn đang cố gắng đạt được điều gì?", "What are you working on?": "Bạn đang làm gì vậy?", @@ -2182,6 +2221,7 @@ "What is shared:": "", "What's New in": "Thông tin mới về", "What's on your mind?": "", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Khi được bật, mô hình sẽ phản hồi từng tin nhắn trò chuyện trong thời gian thực, tạo ra phản hồi ngay khi người dùng gửi tin nhắn. Chế độ này hữu ích cho các ứng dụng trò chuyện trực tiếp, nhưng có thể ảnh hưởng đến hiệu suất trên phần cứng chậm hơn.", "wherever you are": "bất cứ nơi nào bạn đang ở", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", diff --git a/src/lib/i18n/locales/zh-CN/translation.json b/src/lib/i18n/locales/zh-CN/translation.json index a089bb8e01..ce09ad948c 100644 --- a/src/lib/i18n/locales/zh-CN/translation.json +++ b/src/lib/i18n/locales/zh-CN/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "{{user}} 的对话记录", "{{webUIName}} Backend Required": "{{webUIName}} 需要后端服务", "*Prompt node ID(s) are required for image generation": "*图片生成需要提示词节点 ID", + "1 hour before": "", "1 Source": "1 个引用来源", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "刚刚", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "成员可加入的协作频道", "A discussion channel where access is controlled by groups and permissions": "由用户组控制的讨论频道", "A new version (v{{LATEST_VERSION}}) is now available.": "新版本(v{{LATEST_VERSION}})现已发布", @@ -46,6 +51,7 @@ "Access Control": "访问控制", "Access Grants": "访问授权", "Access List": "访问列表", + "Access updated": "", "Accessible to all users": "对所有用户开放", "Account": "账号", "Account Activation Pending": "账号待激活", @@ -71,9 +77,11 @@ "Add content here": "在此添加内容", "Add Custom Parameter": "增加自定义参数", "Add Custom Prompt": "增加自定义提示词", + "Add description": "", "Add Details": "丰富细节", "Add Files": "添加文件", "Add Image": "添加图片", + "Add location": "", "Add Member": "添加成员", "Add Members": "添加成员", "Add Memory": "添加记忆", @@ -109,6 +117,7 @@ "AI": "AI", "All": "全部", "All chats have been unarchived.": "已成功取消全部对话的归档状态。", + "All day": "", "All models are now hidden": "已隐藏全部模型", "All models are now visible": "已显示全部模型", "All models deleted successfully": "已成功删除全部模型", @@ -197,6 +206,7 @@ "Ask a question": "提问", "Assistant": "助手", "Async Embedding Processing": "异步嵌入处理", + "At time of event": "", "Attach File From Knowledge": "引用知识库中的文件", "Attach Files": "添加文件", "Attach Knowledge": "引用知识库", @@ -271,6 +281,8 @@ "Bypass Web Loader": "绕过网页加载器", "Cache Base Model List": "缓存基础模型列表", "Calendar": "日历", + "Calendar deleted": "", + "Calendars": "", "Call": "语音通话", "Call feature is not supported when using Web STT engine": "使用 Web 语音转文字引擎时不支持语音通话功能", "Camera": "摄像头", @@ -407,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "连接到符合 OpenAPI 规范的外部工具服务器", "Connected ({{type}})": "已连接({{type}})", "Connection failed": "连接失败", + "Connection lost. Reconnecting...": "", "Connection successful": "连接成功", "Connection Type": "连接类型", "Connections": "外部连接", @@ -438,6 +451,7 @@ "Copy Last Response": "复制最后一个回答", "Copy link": "复制链接", "Copy Link": "复制链接", + "Copy Path": "", "Copy Prompt": "复制提示词", "Copy Share Link": "复制分享链接", "Copy to clipboard": "复制到剪贴板", @@ -453,7 +467,7 @@ "Create a new note": "新建笔记", "Create Account": "创建账号", "Create Admin Account": "创建管理员账号", - "Create and manage scheduled automations": "", + "Create and manage scheduled automations": "创建和管理计划自动化任务", "Create Channel": "创建频道", "Create Folder": "创建分组", "Create Image": "图片生成", @@ -479,7 +493,7 @@ "Custom Gender": "自定义性别", "Custom Parameter Name": "自定义参数名称", "Custom Parameter Value": "自定义参数值", - "Daily": "", + "Daily": "每日", "Daily Messages": "每日消息数", "Danger Zone": "危险区域", "Dark": "暗色", @@ -518,8 +532,11 @@ "Delete All Chats": "删除所有对话记录", "Delete all contents inside this folder": "删除此分组内的所有内容", "Delete automation?": "要删除此自动化吗?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "删除对话记录", "Delete chat?": "要删除此对话记录吗?", + "Delete Event": "", "Delete File": "删除文件", "Delete folder?": "要删除此分组吗?", "Delete function?": "要删除此函数吗?", @@ -826,6 +843,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "错误:ID 为“{{modelId}}”的模型已存在。请选择不同的模型 ID。", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "错误:模型 ID 不能为空。请输入有效的模型 ID。", "Evaluations": "模型评价", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa 接口密钥", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "例如:(&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "例如:ALL", @@ -874,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "无法连接到终端服务器:{{URL}}", "Failed to copy link": "复制链接失败", "Failed to create API Key.": "创建接口密钥失败", + "Failed to delete calendar": "", "Failed to delete note": "删除笔记失败", "Failed to download image": "图片下载失败", "Failed to extract content from the file: {{error}}": "文件内容提取失败:{{error}}", @@ -970,7 +992,7 @@ "Forward": "前进", "Forwards system user OAuth access token to authenticate": "转发用户的 OAuth 访问令牌(Access Token)以进行身份验证", "Forwards system user session credentials to authenticate": "转发用户的会话凭证(Session Credentials)以进行身份验证", - "Fr_day_of_week": "", + "Fr_day_of_week": "周五", "Full Context Mode": "完整上下文模式", "Function": "函数", "Function Calling": "函数调用 (Function Calling)", @@ -1045,7 +1067,7 @@ "History": "历史记录", "Home": "主页", "Host": "主机", - "Hourly": "", + "Hourly": "每小时", "Hourly Messages": "每小时消息数", "How can I help you today?": "有什么我能帮您的吗?", "How would you rate this response?": "您如何评价这个回答?", @@ -1195,6 +1217,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "搜索并发数限制。默认为 0(无限制),设置为 1 则以顺序执行(推荐用于具有严格速率限制的接口,如 Brave 免费套餐)。", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "限制同时进行的嵌入请求数量,设为 0 表示不限制。", "List": "列表", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "正在倾听...", "Live": "实时", "Llama.cpp": "Llama.cpp", @@ -1205,6 +1228,7 @@ "local": "本地", "Local": "本地", "Local Task Model": "本地任务模型", + "Location": "", "Location access not allowed": "不允许访问位置信息", "Lost": "较差", "Low": "低", @@ -1268,10 +1292,11 @@ "Mistral OCR": "Mistral OCR", "Mistral OCR API Key required.": "需要 Mistral OCR 接口密钥", "MistralAI": "MistralAI", - "Mo_day_of_week": "", + "Mo_day_of_week": "周一", "Model": "模型", "Model '{{modelName}}' has been successfully downloaded.": "模型“{{modelName}}”已成功下载", "Model '{{modelTag}}' is already in queue for downloading.": "模型“{{modelTag}}”已在下载队列中", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "成功删除模型:{{modelName}}", "Model {{modelName}} is not vision capable": "模型 {{modelName}} 不支持视觉能力", "Model {{name}} is now {{status}}": "模型 {{name}} 现在是 {{status}}", @@ -1279,6 +1304,7 @@ "Model {{name}} is now visible": "模型 {{name}} 已可见", "Model accepts file inputs": "模型支持文件输入", "Model accepts image inputs": "模型支持图像输入", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "模型可执行代码并进行计算", "Model can generate images based on text prompts": "模型可根据文本提示生成图像", "Model can search the web for information": "模型可进行联网搜索", @@ -1312,7 +1338,8 @@ "Models Sharing": "分享模型", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Search 接口密钥", - "Monthly": "", + "Month": "", + "Monthly": "每月", "More": "更多", "More Concise": "精炼表达", "More options": "更多选项", @@ -1330,6 +1357,7 @@ "New Automation": "创建自动化任务", "New Button": "新按钮", "New Chat": "新对话", + "New Event": "", "New File": "新建文件", "New Folder": "创建分组", "New Function": "新函数", @@ -1433,7 +1461,7 @@ "Ollama Cloud API Key": "Ollama Cloud 接口密钥", "Ollama Version": "Ollama 版本", "On": "开启", - "Once": "", + "Once": "单次", "OneDrive": "OneDrive", "Only active when \"Paste Large Text as File\" setting is toggled on.": "仅在启用“粘贴超长文本为文件”选项时有效。", "Only active when the chat input is in focus and an LLM is generating a response.": "仅在聚焦对话框且大语言模型正在生成回答时有效。", @@ -1499,6 +1527,7 @@ "Password": "密码", "Passwords do not match.": "两次输入的密码不一致。", "Paste Large Text as File": "粘贴大文本为文件", + "Path copied": "", "Paused": "已暂停", "PDF document (.pdf)": "PDF 文档 (.pdf)", "PDF Extract Images (OCR)": "PDF 图像提取(使用文字识别)", @@ -1518,7 +1547,7 @@ "Persistent": "持久化", "Personalization": "个性化", "Pin": "置顶", - "Pin to Sidebar": "", + "Pin to Sidebar": "固定到侧边栏", "Pinned": "已置顶", "Pinned Messages": "置顶消息", "Pinned Models": "固定在侧边栏的模型", @@ -1606,6 +1635,7 @@ "Reasoning Effort": "推理努力 (Reasoning Effort)", "Reasoning Tags": "推理过程标签", "Recently Used": "最近使用", + "Reconnected": "", "Record": "录制", "Record voice": "录音", "Redirecting you to Open WebUI Community": "正在将您重定向到 Open WebUI 社区", @@ -1629,6 +1659,7 @@ "Relevance": "相关性", "Relevance Threshold": "相关性阈值", "Remember Dismissal": "记住关闭状态", + "Reminder": "", "Remove": "移除", "Remove {{MODELID}} from list.": "从列表中移除 {{MODELID}}", "Remove action": "删除当前操作", @@ -1647,6 +1678,7 @@ "Reply to thread...": "回复主题...", "Replying to {{NAME}}": "回复 {{NAME}}", "required": "必填", + "Reranking Batch Size": "", "Reranking Engine": "重新排名引擎", "Reranking Model": "重新排名模型", "Reset": "重置", @@ -1678,7 +1710,7 @@ "Running": "运行中", "Running...": "运行中...", "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "并行运行嵌入任务以加快处理速度。如果遇到限速问题,请关闭此选项。", - "Sa_day_of_week": "", + "Sa_day_of_week": "周六", "Save": "保存", "Save & Create": "保存并创建", "Save & Update": "保存并更新", @@ -1873,7 +1905,10 @@ "Start a new conversation": "开始新对话", "Start of the channel": "频道起点", "Start Tag": "起始标签", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "正在启动内核...", + "Starting now": "", "State": "状态", "Status": "状态", "Status cleared successfully": "状态已清除", @@ -1895,7 +1930,7 @@ "STT Model": "语音转文本模型", "STT Settings": "语音转文本设置", "Stylized PDF Export": "美化 PDF 导出", - "Su_day_of_week": "", + "Su_day_of_week": "周日", "Submit question": "提交问题", "Submit suggestion": "提交建议", "Subtitle": "副标题", @@ -1941,7 +1976,7 @@ "Text Splitter": "文本切分器", "Text-to-Speech": "文本转语音", "Text-to-Speech Engine": "文本转语音引擎", - "Th_day_of_week": "", + "Th_day_of_week": "周四", "Thanks for your feedback!": "感谢您的反馈!", "The Application Account DN you bind with for search": "您所绑定用于搜索的 Application Account DN", "The base to search for users": "搜索用户的 Base", @@ -1986,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "这将删除{{NAME}}及其所有内容。", "This will delete all models including custom models": "这将删除所有模型,包括自定义模型", "This will delete all models including custom models and cannot be undone.": "这将删除所有模型,包括自定义模型,且无法撤销。", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "这将重置知识库并同步所有文件。确认继续?", "Thorough explanation": "解释详尽", "Thought": "思考过程", @@ -2005,6 +2041,7 @@ "Title cannot be an empty string.": "标题不能为空", "Title Generation": "标题生成", "Title Generation Prompt": "用于自动生成标题的提示词", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "访问可下载的模型名称,", "To access the GGUF models available for downloading,": "访问可下载的 GGUF 模型,", @@ -2055,7 +2092,7 @@ "TTS Model": "文本转语音模型", "TTS Settings": "文本转语音设置", "TTS Voice": "文本转语音音色", - "Tu_day_of_week": "", + "Tu_day_of_week": "周二", "Type": "类型", "Type here...": "请输入内容...", "Type Hugging Face Resolve (Download) URL": "输入 Hugging Face 模型解析(下载)地址", @@ -2071,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} 后卸载", "Unlock mysteries": "解码未知", "Unpin": "取消置顶", + "Unpin from Sidebar": "", "Unravel secrets": "冲破奥秘", "Unshare Chat": "取消分享对话", "Unsupported file type.": "不支持的文件类型", @@ -2158,7 +2196,7 @@ "Warning: Enabling this will allow users to run scheduled prompts automatically.": "警告:启用后将允许用户自动执行定时提示词任务。", "Warning: Enabling this will allow users to upload arbitrary code on the server.": "警告:启用此功能将允许用户在服务器上上传任意代码", "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "警告:启用 Jupyter 执行将允许运行任意代码,存在严重安全风险——务必谨慎操作", - "We_day_of_week": "", + "We_day_of_week": "周三", "Web": "网页", "Web API": "网页 API", "Web Loader Engine": "网页加载引擎", @@ -2175,13 +2213,15 @@ "WebUI will make requests to \"{{url}}\"": "WebUI 将向 \"{{url}}\" 发出请求", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI 将向 \"{{url}}/api/chat\" 发出请求", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI 将向 \"{{url}}/chat/completions\" 发出请求", - "Weekly": "", + "Week": "", + "Weekly": "每周", "What are you trying to achieve?": "您想要达到什么目标?", "What are you working on?": "您在忙于什么?", "What is NOT shared:": "不共享的内容:", "What is shared:": "共享的内容:", "What's New in": "最近更新内容于", "What's on your mind?": "聊聊您的想法吧!", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "启用后,模型将实时回答每条对话信息,在用户发送信息后立即生成回答。这种模式适用于即时对话应用,但在性能较低的设备上可能会影响响应速度", "wherever you are": "纵使身在远方,亦与世界同频", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "是否对输出内容进行分页。每页之间将用水平分隔线和页码隔开。默认为关闭", diff --git a/src/lib/i18n/locales/zh-TW/translation.json b/src/lib/i18n/locales/zh-TW/translation.json index f90782c3f6..50d352a96f 100644 --- a/src/lib/i18n/locales/zh-TW/translation.json +++ b/src/lib/i18n/locales/zh-TW/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "{{user}} 的對話", "{{webUIName}} Backend Required": "需要提供 {{webUIName}} 後端", "*Prompt node ID(s) are required for image generation": "* 產生圖片需要提示詞節點 ID", + "1 hour before": "", "1 Source": "1 個來源", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "剛剛", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "成員可加入的協作頻道", "A discussion channel where access is controlled by groups and permissions": "由權限組控制的討論頻道", "A new version (v{{LATEST_VERSION}}) is now available.": "新版本 (v{{LATEST_VERSION}}) 已釋出。", @@ -46,6 +51,7 @@ "Access Control": "存取控制", "Access Grants": "存取授權", "Access List": "存取清單", + "Access updated": "", "Accessible to all users": "所有使用者皆可存取", "Account": "帳號", "Account Activation Pending": "帳號待啟用", @@ -71,9 +77,11 @@ "Add content here": "在此新增內容", "Add Custom Parameter": "新增自訂參數", "Add Custom Prompt": "新增自訂提示詞", + "Add description": "", "Add Details": "豐富細節", "Add Files": "新增檔案", "Add Image": "新增圖片", + "Add location": "", "Add Member": "新增成員", "Add Members": "新增成員", "Add Memory": "新增記憶", @@ -109,6 +117,7 @@ "AI": "AI", "All": "全部", "All chats have been unarchived.": "已成功將所有對話解除封存。", + "All day": "", "All models are now hidden": "已隱藏全部模型", "All models are now visible": "已顯示全部模型", "All models deleted successfully": "成功刪除所有模型", @@ -197,6 +206,7 @@ "Ask a question": "提出問題", "Assistant": "助理", "Async Embedding Processing": "非同步嵌入處理", + "At time of event": "", "Attach File From Knowledge": "從知識庫附加檔案", "Attach Files": "新增檔案", "Attach Knowledge": "附加知識庫", @@ -271,6 +281,8 @@ "Bypass Web Loader": "繞過網頁載入器", "Cache Base Model List": "快取基礎模型清單", "Calendar": "日曆", + "Calendar deleted": "", + "Calendars": "", "Call": "通話", "Call feature is not supported when using Web STT engine": "使用網頁語音辨識 (Web STT) 引擎時不支援通話功能", "Camera": "相機", @@ -407,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "連線至您自有或其他與 OpenAPI 相容的外部工具伺服器。", "Connected ({{type}})": "已連線({{type}})", "Connection failed": "連線失敗", + "Connection lost. Reconnecting...": "", "Connection successful": "連線成功", "Connection Type": "連線類型", "Connections": "連線", @@ -438,6 +451,7 @@ "Copy Last Response": "複製最後的回應", "Copy link": "複製連結", "Copy Link": "複製連結", + "Copy Path": "", "Copy Prompt": "複製提示詞", "Copy Share Link": "複製分享連結", "Copy to clipboard": "複製到剪貼簿", @@ -453,7 +467,7 @@ "Create a new note": "新建筆記", "Create Account": "建立帳號", "Create Admin Account": "建立管理員帳號", - "Create and manage scheduled automations": "", + "Create and manage scheduled automations": "建立和管理計畫自動化任務", "Create Channel": "建立頻道", "Create Folder": "建立分組", "Create Image": "產生圖片", @@ -479,7 +493,7 @@ "Custom Gender": "自訂性別", "Custom Parameter Name": "自訂參數名稱", "Custom Parameter Value": "自訂參數值", - "Daily": "", + "Daily": "每日", "Daily Messages": "每日訊息數", "Danger Zone": "危險區域", "Dark": "深色", @@ -518,8 +532,11 @@ "Delete All Chats": "刪除所有對話紀錄", "Delete all contents inside this folder": "刪除此資料夾內的所有內容", "Delete automation?": "要刪除此自動化嗎?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "刪除對話紀錄", "Delete chat?": "刪除對話紀錄?", + "Delete Event": "", "Delete File": "刪除檔案", "Delete folder?": "刪除資料夾?", "Delete function?": "刪除函式?", @@ -826,6 +843,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "錯誤:ID 為「{{modelId}}」的模型已存在。請選擇不同的模型 ID。", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "錯誤:模型 ID 不能為空。請輸入有效的模型 ID。", "Evaluations": "評估", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API 金鑰", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "範例:(&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "範例:ALL", @@ -874,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "無法連線至終端伺服器:{{URL}}", "Failed to copy link": "複製連結失敗", "Failed to create API Key.": "建立 API 金鑰失敗。", + "Failed to delete calendar": "", "Failed to delete note": "刪除筆記失敗", "Failed to download image": "圖片下載失敗", "Failed to extract content from the file: {{error}}": "檔案內容擷取失敗:{{error}}", @@ -970,7 +992,7 @@ "Forward": "前進", "Forwards system user OAuth access token to authenticate": "轉發使用者 OAuth 存取權杖(Access Token)以進行驗證", "Forwards system user session credentials to authenticate": "轉發使用者工作階段憑證(Session Credentials)以進行驗證", - "Fr_day_of_week": "", + "Fr_day_of_week": "週五", "Full Context Mode": "完整上下文模式", "Function": "函式", "Function Calling": "函式呼叫", @@ -1045,7 +1067,7 @@ "History": "歷史紀錄", "Home": "首頁", "Host": "主機", - "Hourly": "", + "Hourly": "每小時", "Hourly Messages": "每小時訊息數", "How can I help you today?": "今天我能為您做些什麼?", "How would you rate this response?": "您如何評價此回應?", @@ -1195,6 +1217,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "平行搜尋數量限制。預設為 0(無限制),設定為 1 則以順序執行(建議用於具有嚴格速率限制的服務,如 Brave 免費方案)。", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "限制同時進行的嵌入請求數量,設為 0 表示不限制。", "List": "列表", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "正在聆聽...", "Live": "即時", "Llama.cpp": "Llama.cpp", @@ -1205,6 +1228,7 @@ "local": "本機", "Local": "本機", "Local Task Model": "本機任務模型", + "Location": "", "Location access not allowed": "位置存取未獲允許", "Lost": "落敗", "Low": "低", @@ -1268,10 +1292,11 @@ "Mistral OCR": "Mistral OCR", "Mistral OCR API Key required.": "需要提供 Mistral OCR API 金鑰。", "MistralAI": "MistralAI", - "Mo_day_of_week": "", + "Mo_day_of_week": "週一", "Model": "模型", "Model '{{modelName}}' has been successfully downloaded.": "模型「{{modelName}}」已成功下載。", "Model '{{modelTag}}' is already in queue for downloading.": "模型「{{modelTag}}」已在下載佇列中。", + "Model {{modelId}} not found": "", "Model {{modelName}} deleted successfully": "模型 {{modelName}} 已成功刪除", "Model {{modelName}} is not vision capable": "模型 {{modelName}} 不具備視覺能力", "Model {{name}} is now {{status}}": "模型 {{name}} 現在狀態為 {{status}}", @@ -1279,6 +1304,7 @@ "Model {{name}} is now visible": "模型 {{name}} 已顯示", "Model accepts file inputs": "模型支援檔案輸入", "Model accepts image inputs": "模型接受影像輸入", + "Model can access Open Terminal for command execution and file management": "", "Model can execute code and perform calculations": "模型可執行程式碼並進行運算", "Model can generate images based on text prompts": "模型可根據文字提示詞產生影像", "Model can search the web for information": "模型可透過網路搜尋資訊", @@ -1312,7 +1338,8 @@ "Models Sharing": "分享模型", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek 搜尋 API 金鑰", - "Monthly": "", + "Month": "", + "Monthly": "每月", "More": "更多", "More Concise": "精煉表達", "More options": "更多選項", @@ -1330,6 +1357,7 @@ "New Automation": "新增自動化", "New Button": "新按鈕", "New Chat": "新增對話", + "New Event": "", "New File": "新增檔案", "New Folder": "新增資料夾", "New Function": "新增函式", @@ -1433,7 +1461,7 @@ "Ollama Cloud API Key": "Ollama Cloud API 金鑰", "Ollama Version": "Ollama 版本", "On": "開啟", - "Once": "", + "Once": "一次", "OneDrive": "OneDrive", "Only active when \"Paste Large Text as File\" setting is toggled on.": "僅在啟用「將大型文字作為檔案貼上」設定時有效。", "Only active when the chat input is in focus and an LLM is generating a response.": "僅在對話輸入框聚焦且大型語言模型正在產生回應時有效。", @@ -1499,6 +1527,7 @@ "Password": "密碼", "Passwords do not match.": "兩次輸入的密碼不一致。", "Paste Large Text as File": "將大型文字以檔案貼上", + "Path copied": "", "Paused": "已暫停", "PDF document (.pdf)": "PDF 檔案 (.pdf)", "PDF Extract Images (OCR)": "PDF 影像擷取(OCR 光學文字辨識)", @@ -1518,7 +1547,7 @@ "Persistent": "持久性", "Personalization": "個人化", "Pin": "釘選", - "Pin to Sidebar": "", + "Pin to Sidebar": "固定到側邊欄", "Pinned": "已釘選", "Pinned Messages": "置頂訊息", "Pinned Models": "固定於側邊欄的模型", @@ -1606,6 +1635,7 @@ "Reasoning Effort": "推理程度", "Reasoning Tags": "推理標籤", "Recently Used": "最近使用", + "Reconnected": "", "Record": "錄製", "Record voice": "錄音", "Redirecting you to Open WebUI Community": "正在將您重導向至 Open WebUI 社群", @@ -1629,6 +1659,7 @@ "Relevance": "相關性", "Relevance Threshold": "相關性閾值", "Remember Dismissal": "記住關閉狀態", + "Reminder": "", "Remove": "移除", "Remove {{MODELID}} from list.": "從清單中移除 {{MODELID}}", "Remove action": "刪除目前操作", @@ -1647,6 +1678,7 @@ "Reply to thread...": "回覆討論串...", "Replying to {{NAME}}": "回覆 {{NAME}}", "required": "必填", + "Reranking Batch Size": "", "Reranking Engine": "重新排序引擎", "Reranking Model": "重新排序模型", "Reset": "重設", @@ -1678,7 +1710,7 @@ "Running": "正在執行", "Running...": "正在執行...", "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "同時執行嵌入任務以加快處理速度。如果遇到速率限制問題,請關閉此功能。", - "Sa_day_of_week": "", + "Sa_day_of_week": "週六", "Save": "儲存", "Save & Create": "儲存並建立", "Save & Update": "儲存並更新", @@ -1873,7 +1905,10 @@ "Start a new conversation": "開始新對話", "Start of the channel": "頻道起點", "Start Tag": "起始標籤", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "正在啟動核心…", + "Starting now": "", "State": "狀態", "Status": "狀態", "Status cleared successfully": "狀態已清除", @@ -1895,7 +1930,7 @@ "STT Model": "語音轉文字 (STT) 模型", "STT Settings": "語音轉文字 (STT) 設定", "Stylized PDF Export": "風格化 PDF 匯出", - "Su_day_of_week": "", + "Su_day_of_week": "週日", "Submit question": "提交問題", "Submit suggestion": "提交建議", "Subtitle": "副標題", @@ -1941,7 +1976,7 @@ "Text Splitter": "文字分割器", "Text-to-Speech": "文字轉語音", "Text-to-Speech Engine": "文字轉語音引擎", - "Th_day_of_week": "", + "Th_day_of_week": "週四", "Thanks for your feedback!": "感謝您的回饋!", "The Application Account DN you bind with for search": "您綁定用於搜尋的應用程式帳號 DN", "The base to search for users": "搜尋使用者的基礎", @@ -1986,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "這將會刪除 {{NAME}}其所有內容。", "This will delete all models including custom models": "這將刪除所有模型,包括自訂模型", "This will delete all models including custom models and cannot be undone.": "這將刪除所有模型,包括自訂模型,且無法復原。", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "這將重設知識庫並同步所有檔案。您確定要繼續嗎?", "Thorough explanation": "詳細解釋", "Thought": "思考過程", @@ -2005,6 +2041,7 @@ "Title cannot be an empty string.": "標題不能是空字串。", "Title Generation": "產生標題", "Title Generation Prompt": "產生標題的提示詞", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "若要存取可供下載的模型名稱,", "To access the GGUF models available for downloading,": "若要存取可供下載的 GGUF 模型,", @@ -2055,7 +2092,7 @@ "TTS Model": "文字轉語音 (TTS) 模型", "TTS Settings": "文字轉語音 (TTS) 設定", "TTS Voice": "文字轉語音 (TTS) 聲音", - "Tu_day_of_week": "", + "Tu_day_of_week": "週二", "Type": "類型", "Type here...": "在此輸入...", "Type Hugging Face Resolve (Download) URL": "輸入 Hugging Face 的解析(下載)URL", @@ -2071,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "於 {{FROM_NOW}} 後解除載入", "Unlock mysteries": "解鎖謎題", "Unpin": "取消釘選", + "Unpin from Sidebar": "", "Unravel secrets": "揭開秘密", "Unshare Chat": "取消分享對話", "Unsupported file type.": "不支援的檔案類型", @@ -2158,7 +2196,7 @@ "Warning: Enabling this will allow users to run scheduled prompts automatically.": "警告:啟用後將允許使用者自動執行排程提示詞。", "Warning: Enabling this will allow users to upload arbitrary code on the server.": "警告:啟用此功能將允許使用者在伺服器上上傳任意程式碼。", "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "警告:Jupyter 執行允許任意程式碼執行,構成嚴重安全風險 —— 請務必極度謹慎。", - "We_day_of_week": "", + "We_day_of_week": "週三", "Web": "網頁", "Web API": "網頁 API", "Web Loader Engine": "網頁載入引擎", @@ -2175,13 +2213,15 @@ "WebUI will make requests to \"{{url}}\"": "WebUI 將向 \"{{url}}\" 傳送請求", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI 將向 \"{{url}}/api/chat\" 傳送請求", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI 將向 \"{{url}}/chat/completions\" 傳送請求", - "Weekly": "", + "Week": "", + "Weekly": "每週", "What are you trying to achieve?": "您正在試圖完成什麼?", "What are you working on?": "您現在的工作是什麼?", "What is NOT shared:": "不會分享的內容:", "What is shared:": "會分享的內容:", "What's New in": "新功能", "What's on your mind?": "聊聊您的想法?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "啟用時,模型將即時回應每個對話訊息,在使用者傳送訊息後立即產生回應。此模式適用於即時對話應用程式,但在較慢的硬體上可能會影響效能。", "wherever you are": "無論您在何處", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "是否啟用輸出分頁功能,每頁會以水平線與頁碼分隔。預設為 False。", diff --git a/src/lib/stores/index.ts b/src/lib/stores/index.ts index a59944f50c..db779a7b84 100644 --- a/src/lib/stores/index.ts +++ b/src/lib/stores/index.ts @@ -29,6 +29,7 @@ export const MODEL_DOWNLOAD_POOL = writable({}); export const mobile = writable(false); export const socket: Writable = writable(null); +export const socketConnected: Writable = writable(true); export const activeUserIds: Writable = writable(null); export const activeChatIds: Writable> = writable(new Set()); export const USAGE_POOL: Writable = writable(null); @@ -230,6 +231,7 @@ type Settings = { ctrlEnterToSend?: boolean; renderMarkdownInPreviews?: boolean; recentEmojis?: string[]; + pinnedMenuItems?: string[]; system?: string; seed?: number; diff --git a/src/lib/utils/audio.ts b/src/lib/utils/audio.ts index 6effbc4137..94da18af67 100644 --- a/src/lib/utils/audio.ts +++ b/src/lib/utils/audio.ts @@ -1,32 +1,39 @@ +type AudioQueueEvent = 'stop' | 'empty-queue' | 'id-change'; + +interface AudioQueueStopDetail { + event: AudioQueueEvent; + id: string | null; +} + +export type OnStoppedCallback = (detail: AudioQueueStopDetail) => void; + export class AudioQueue { - constructor(audioElement) { + private audio: HTMLAudioElement; + private queue: string[] = []; + private current: string | null = null; + private readonly _onEnded = () => this.next(); + + id: string | null = null; + onStopped: OnStoppedCallback | null = null; + + constructor(audioElement: HTMLAudioElement) { this.audio = audioElement; - this.queue = []; - this.current = null; - this.id = null; - - this._onEnded = () => this.next(); this.audio.addEventListener('ended', this._onEnded); - - this.onStopped = null; // optional callback } - setId(newId) { - console.log('Setting audio queue ID to:', newId); - if (this.id !== newId) { - this.stop(); - this.id = newId; - if (this.onStopped) this.onStopped({ event: 'id-change', id: newId }); - } + setId(newId: string) { + if (this.id === newId) return; + + this.#halt(); + this.id = newId; + this.onStopped?.({ event: 'id-change', id: newId }); } - setPlaybackRate(rate) { - console.log('Setting audio playback rate to:', rate); + setPlaybackRate(rate: number) { this.audio.playbackRate = rate; } - enqueue(url) { - console.log('Enqueuing audio URL:', url); + enqueue(url: string) { this.queue.push(url); // Auto-play if nothing is currently playing or loaded @@ -44,30 +51,37 @@ export class AudioQueue { } next() { - this.current = this.queue.shift(); + this.current = this.queue.shift() ?? null; + if (this.current) { this.audio.src = this.current; this.audio.play(); - console.log('Playing audio URL:', this.current); } else { - this.stop(); - if (this.onStopped) this.onStopped({ event: 'empty-queue', id: this.id }); + this.#halt(); + this.onStopped?.({ event: 'empty-queue', id: this.id }); } } stop() { + this.#halt(); + this.onStopped?.({ event: 'stop', id: this.id }); + } + + destroy() { + this.audio.removeEventListener('ended', this._onEnded); + this.#halt(); + this.onStopped = null; + } + + /** + * Pause audio and clear queue without firing onStopped. + * Callers that need the callback should invoke it themselves. + */ + #halt() { this.audio.pause(); this.audio.currentTime = 0; this.audio.src = ''; this.queue = []; this.current = null; - if (this.onStopped) this.onStopped({ event: 'stop', id: this.id }); - } - - destroy() { - this.audio.removeEventListener('ended', this._onEnded); - this.stop(); - this.onStopped = null; - this.audio = null; } } diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts index ecaeefab04..1820e70481 100644 --- a/src/lib/utils/index.ts +++ b/src/lib/utils/index.ts @@ -677,7 +677,9 @@ export const calculateSHA256 = async (file) => { export const getImportOrigin = (_chats) => { // Check what external service chat imports are from - if ('mapping' in _chats[0]) { + // ChatGPT exports may include folder/project metadata entries without 'mapping', + // so we check if ANY item has a 'mapping' key instead of only the first one. + if (_chats.some((chat) => 'mapping' in chat)) { return 'openai'; } return 'webui'; @@ -706,6 +708,21 @@ export const getUserPosition = async (raw = false) => { } }; +const extractOpenAIMessageContent = (message): string => { + // Extract text content from a ChatGPT message, handling various content formats + // (string parts, object parts like DALL-E images, text field fallback) + try { + const parts = message?.['content']?.['parts']; + if (Array.isArray(parts)) { + const textParts = parts.filter((p) => typeof p === 'string'); + if (textParts.length > 0) return textParts.join('\n'); + } + return message?.['content']?.['text'] || ''; + } catch { + return ''; + } +}; + const convertOpenAIMessages = (convo) => { // Parse OpenAI chat messages and create chat dictionary for creating new chats const mapping = convo['mapping']; @@ -726,15 +743,18 @@ const convertOpenAIMessages = (convo) => { // Skip chat messages with no content continue; } else { + const role = message['message']?.['author']?.['role']; + // Skip system and tool messages — they don't map to user/assistant + if (role === 'system' || role === 'tool') { + continue; + } + const new_chat = { id: message_id, parentId: lastId, childrenIds: message['children'] || [], - role: message['message']?.['author']?.['role'] !== 'user' ? 'assistant' : 'user', - content: - message['message']?.['content']?.['parts']?.[0] || - message['message']?.['content']?.['text'] || - '', + role: role !== 'user' ? 'assistant' : 'user', + content: extractOpenAIMessageContent(message['message']), model: 'gpt-3.5-turbo', done: true, context: null @@ -747,6 +767,12 @@ const convertOpenAIMessages = (convo) => { } } + // Fix up the last message's childrenIds to be empty (it's the leaf node in our + // linear chain regardless of what the original tree structure had) + if (messages.length > 0) { + messages[messages.length - 1].childrenIds = []; + } + const history: Record = {}; messages.forEach((obj) => (history[obj.id] = obj)); @@ -773,18 +799,6 @@ const validateChat = (chat) => { return false; } - // Last message's children should be an empty array - const lastMessage = messages[messages.length - 1]; - if (lastMessage.childrenIds.length !== 0) { - return false; - } - - // First message's parent should be null - const firstMessage = messages[0]; - if (firstMessage.parentId !== null) { - return false; - } - // Every message's content should be a string for (const message of messages) { if (typeof message.content !== 'string') { @@ -799,7 +813,18 @@ export const convertOpenAIChats = (_chats) => { // Create a list of dictionaries with each conversation from import const chats = []; let failed = 0; + let skipped = 0; for (const convo of _chats) { + // Skip folder/project metadata entries that lack a 'mapping' key + if (!('mapping' in convo)) { + skipped++; + console.log( + 'Skipping non-conversation entry (folder/project):', + convo['title'] ?? convo['id'] + ); + continue; + } + const chat = convertOpenAIMessages(convo); if (validateChat(chat)) { @@ -815,6 +840,9 @@ export const convertOpenAIChats = (_chats) => { } } console.log(failed, 'Conversations could not be imported'); + if (skipped > 0) { + console.log(skipped, 'Non-conversation entries (folders/projects) were skipped'); + } return chats; }; @@ -1713,13 +1741,33 @@ export const initMermaid = async () => { return mermaid; }; -export const renderMermaidDiagram = async (mermaid, code: string) => { - const parseResult = await mermaid.parse(code, { suppressErrors: false }); - if (parseResult) { - const { svg } = await mermaid.render(`mermaid-${uuidv4()}`, code); - return svg; +const cleanupMermaidTempElements = (id: string) => { + if (typeof document === 'undefined') { + return; + } + + document.getElementById(id)?.remove(); + document.getElementById(`d${id}`)?.remove(); + document.getElementById(`i${id}`)?.remove(); +}; + +export const renderMermaidDiagram = async ( + mermaid: typeof import('mermaid').default, + code: string, + renderId?: string +) => { + const id = renderId ?? `mermaid-${uuidv4()}`; + try { + const parseResult = await mermaid.parse(code, { suppressErrors: false }); + if (parseResult) { + const { svg } = await mermaid.render(id, code); + return svg; + } + return ''; + } finally { + // Mermaid can leave temporary d*/i* wrappers on error paths. + cleanupMermaidTempElements(id); } - return ''; }; export const renderVegaVisualization = async (spec: string, i18n?: any) => { diff --git a/src/routes/(app)/automations/+page.svelte b/src/routes/(app)/automations/+page.svelte index e48dd3be37..406510e68f 100644 --- a/src/routes/(app)/automations/+page.svelte +++ b/src/routes/(app)/automations/+page.svelte @@ -165,7 +165,10 @@ }; onMount(async () => { - if ($user?.role !== 'admin' && !($user?.permissions?.features?.automations ?? false)) { + if ( + !$config?.features?.enable_automations || + ($user?.role !== 'admin' && !($user?.permissions?.features?.automations ?? false)) + ) { goto('/'); return; } diff --git a/src/routes/(app)/automations/[id]/+page.svelte b/src/routes/(app)/automations/[id]/+page.svelte index 51745fa01e..5e9f71b70c 100644 --- a/src/routes/(app)/automations/[id]/+page.svelte +++ b/src/routes/(app)/automations/[id]/+page.svelte @@ -4,7 +4,7 @@ import { onMount, getContext } from 'svelte'; import { page } from '$app/stores'; - import { user, showSidebar } from '$lib/stores'; + import { user, showSidebar, config } from '$lib/stores'; import { getAutomationById } from '$lib/apis/automations'; import AutomationEditor from '$lib/components/automations/AutomationEditor.svelte'; @@ -18,7 +18,10 @@ $: automationId = $page.params.id; onMount(async () => { - if ($user?.role !== 'admin' && !($user?.permissions?.features?.automations ?? false)) { + if ( + !$config?.features?.enable_automations || + ($user?.role !== 'admin' && !($user?.permissions?.features?.automations ?? false)) + ) { goto('/'); return; } diff --git a/src/routes/(app)/calendar/+page.svelte b/src/routes/(app)/calendar/+page.svelte new file mode 100644 index 0000000000..ec61a27eb9 --- /dev/null +++ b/src/routes/(app)/calendar/+page.svelte @@ -0,0 +1,378 @@ + + + + {$i18n.t('Calendar')} • {$WEBUI_NAME} + + + refresh()} + on:delete={() => refresh()} +/> + +
+ {#if loaded} + + + +
+ + + + +
+ +
+
+ {:else} +
+ +
+ {/if} +
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 8aeda16594..0dc8170eef 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -19,6 +19,7 @@ WEBUI_DEPLOYMENT_ID, mobile, socket, + socketConnected, chatId, chats, currentChatPage, @@ -51,7 +52,7 @@ import 'tippy.js/dist/tippy.css'; import { executeToolServer, getBackendConfig, getModels, getVersion } from '$lib/apis'; - import { getSessionUser, userSignOut } from '$lib/apis/auths'; + import { getSessionUser, updateUserTimezone, userSignOut } from '$lib/apis/auths'; import { getAllTags, getChatList } from '$lib/apis/chats'; import { chatCompletion } from '$lib/apis/openai'; import { @@ -62,7 +63,7 @@ } from '$lib/utils/connections'; import { WEBUI_API_BASE_URL, WEBUI_BASE_URL, WEBUI_HOSTNAME } from '$lib/constants'; - import { bestMatchingLanguage, displayFileHandler } from '$lib/utils'; + import { bestMatchingLanguage, displayFileHandler, getUserTimezone } from '$lib/utils'; import { setTextScale } from '$lib/utils/text-scale'; import NotificationToast from '$lib/components/NotificationToast.svelte'; @@ -127,8 +128,17 @@ console.log('connect_error', err); }); + let hasConnectedOnce = false; + _socket.on('connect', async () => { console.log('connected', _socket.id); + + if (hasConnectedOnce) { + socketConnected.set(true); + toast.success($i18n.t('Reconnected')); + } + hasConnectedOnce = true; + const res = await getVersion(localStorage.token); const deploymentId = res?.deployment_id ?? null; @@ -182,6 +192,8 @@ _socket.on('disconnect', (reason, details) => { console.log(`Socket ${_socket.id} disconnected due to ${reason}`); + socketConnected.set(false); + toast.warning($i18n.t('Connection lost. Reconnecting...')); if (heartbeatInterval) { clearInterval(heartbeatInterval); @@ -425,13 +437,13 @@ return; } - let isFocused = document.visibilityState !== 'visible'; + let isInBackground = document.visibilityState !== 'visible'; if (window.electronAPI) { const res = await window.electronAPI.send({ type: 'window:isFocused' }); if (res) { - isFocused = res.isFocused; + isInBackground = !res.isFocused; } } @@ -439,7 +451,39 @@ const type = event?.data?.type ?? null; const data = event?.data?.data ?? null; - if ((event.chat_id !== $chatId && !$temporaryChatEnabled) || isFocused) { + // Calendar alerts are not chat-scoped — handle before chat_id checks + if (type === 'calendar:alert' && data) { + const timeStr = + data.minutes_until <= 0 + ? $i18n.t('Starting now') + : data.minutes_until === 1 + ? $i18n.t('Starting in 1 minute') + : $i18n.t('Starting in {{count}} minutes', { count: data.minutes_until }); + + toast.custom(NotificationToast, { + componentProps: { + onClick: () => { + goto('/calendar'); + }, + title: data.title, + content: timeStr + }, + duration: 30000, + unstyled: true + }); + + if ($isLastActiveTab) { + if ($settings?.notificationEnabled ?? false) { + new Notification(`${data.title} • Open WebUI`, { + body: timeStr, + icon: `${WEBUI_BASE_URL}/static/favicon.png` + }); + } + } + return; + } + + if ((event.chat_id !== $chatId && !$temporaryChatEnabled) || isInBackground) { if (type === 'chat:completion') { const { done, content, title } = data; const displayTitle = title || $i18n.t('New Chat'); @@ -607,17 +651,17 @@ // check url path const channel = $page.url.pathname.includes(`/channels/${event.channel_id}`); - let isFocused = document.visibilityState !== 'visible'; + let isInBackground = document.visibilityState !== 'visible'; if (window.electronAPI) { const res = await window.electronAPI.send({ type: 'window:isFocused' }); if (res) { - isFocused = res.isFocused; + isInBackground = !res.isFocused; } } - if ((!channel || isFocused) && event?.user?.id !== $user?.id) { + if ((!channel || isInBackground) && event?.user?.id !== $user?.id) { await tick(); const type = event?.data?.type ?? null; const data = event?.data?.data ?? null; @@ -989,6 +1033,12 @@ console.error('Error refreshing backend config:', error); } + // Keep user timezone in sync on every app load/refresh + const timezone = getUserTimezone(); + if (timezone) { + updateUserTimezone(localStorage.token, timezone); + } + // Relay auth token to desktop app for API access if (window.electronAPI?.send) { window.electronAPI diff --git a/static/favicon.png b/static/favicon.png index 63735ad461..10c84f440c 100644 Binary files a/static/favicon.png and b/static/favicon.png differ diff --git a/static/static/favicon.ico b/static/static/favicon.ico index 14c5f9c6d4..b819d42f96 100644 Binary files a/static/static/favicon.ico and b/static/static/favicon.ico differ diff --git a/static/static/favicon.png b/static/static/favicon.png index 63735ad461..10c84f440c 100644 Binary files a/static/static/favicon.png and b/static/static/favicon.png differ