From f36a1d1013b7baede115c3a8cdb92cee18bd050f Mon Sep 17 00:00:00 2001 From: Nguyen Van Qui Date: Wed, 30 Sep 2026 14:47:22 +0700 Subject: [PATCH] feat(i18n): add comprehensive Vietnamese (vi-VN) localization - Add 6,547 translation keys in frontend/src/i18n/locales/vi-VN.ts - Register vi-VN in Vue i18n configs and runtime selectors (Login, Settings, AgentEmbed, IMChannel) - Whitelist vi-VN in frontend docker-entrypoint.sh - Register Vietnamese language support in Go backend (internal/types/locale, internal/types/context_helpers, internal/handler/mcp_usage_instructions) - Fully synced with latest Tencent/WeKnora upstream (bccb4b1) with 0 missing keys and 0 variable mismatches --- frontend/docker-entrypoint.sh | 2 +- frontend/src/api/agent/index.ts | 2 +- frontend/src/api/embed/index.ts | 2 +- .../src/components/AgentEmbedChannelPanel.vue | 1 + frontend/src/components/IMChannelPanel.vue | 1 + frontend/src/i18n/embed.ts | 4 +- frontend/src/i18n/index.ts | 4 +- frontend/src/i18n/localeKeyAudit.test.ts | 1 + frontend/src/i18n/localeKeyAudit.ts | 4 +- frontend/src/i18n/locales/en-US.ts | 1 + frontend/src/i18n/locales/vi-VN.ts | 7819 +++++++++++++++++ frontend/src/i18n/resolveDefaultLocale.ts | 2 +- frontend/src/views/auth/Login.vue | 1 + .../src/views/settings/GeneralSettings.vue | 1 + internal/handler/mcp_usage_instructions.go | 2 +- internal/types/context_helpers.go | 2 + internal/types/locale.go | 1 + 17 files changed, 7842 insertions(+), 8 deletions(-) create mode 100644 frontend/src/i18n/locales/vi-VN.ts diff --git a/frontend/docker-entrypoint.sh b/frontend/docker-entrypoint.sh index 8847445e71b..07d2e448d33 100644 --- a/frontend/docker-entrypoint.sh +++ b/frontend/docker-entrypoint.sh @@ -3,7 +3,7 @@ # Only emit whitelisted locale tags to avoid config.js injection from env values. RUNTIME_DEFAULT_LOCALE="" case "${DEFAULT_LOCALE:-}" in - zh-CN|en-US|ru-RU|ko-KR|ja-JP) RUNTIME_DEFAULT_LOCALE="${DEFAULT_LOCALE}" ;; + zh-CN|en-US|vi-VN|ru-RU|ko-KR|ja-JP) RUNTIME_DEFAULT_LOCALE="${DEFAULT_LOCALE}" ;; esac # 生成运行时配置文件,注入环境变量到前端 diff --git a/frontend/src/api/agent/index.ts b/frontend/src/api/agent/index.ts index 457e1316fb9..d222b7c9b84 100644 --- a/frontend/src/api/agent/index.ts +++ b/frontend/src/api/agent/index.ts @@ -316,7 +316,7 @@ export interface IMChannel { enabled: boolean; mode: 'webhook' | 'websocket' | 'longpoll'; output_mode: 'stream' | 'full'; - locale?: '' | 'zh-CN' | 'en-US' | 'ko-KR' | 'ja-JP' | 'ru-RU'; + locale?: '' | 'zh-CN' | 'en-US' | 'ko-KR' | 'ja-JP' | 'ru-RU' | 'vi-VN'; session_mode?: 'user' | 'thread'; knowledge_base_id?: string; credentials: Record; diff --git a/frontend/src/api/embed/index.ts b/frontend/src/api/embed/index.ts index c579e2489e6..98263fbb113 100644 --- a/frontend/src/api/embed/index.ts +++ b/frontend/src/api/embed/index.ts @@ -47,7 +47,7 @@ export interface EmbedChannelPublicConfig { default_locale?: string } -export type EmbedLocaleTag = 'zh-CN' | 'en-US' | 'ko-KR' | 'ja-JP' | 'ru-RU' | '' +export type EmbedLocaleTag = 'zh-CN' | 'en-US' | 'ko-KR' | 'ja-JP' | 'ru-RU' | 'vi-VN' | '' export interface EmbedChannelStats { session_count: number diff --git a/frontend/src/components/AgentEmbedChannelPanel.vue b/frontend/src/components/AgentEmbedChannelPanel.vue index 041199aff0f..e2cd76281bb 100644 --- a/frontend/src/components/AgentEmbedChannelPanel.vue +++ b/frontend/src/components/AgentEmbedChannelPanel.vue @@ -539,6 +539,7 @@ const defaultLocaleOptions = computed(() => ([ { label: t('embedPublish.defaultLocaleBrowser'), value: '' }, { label: '简体中文', value: 'zh-CN' }, { label: 'English', value: 'en-US' }, + { label: 'Tiếng Việt', value: 'vi-VN' }, { label: '한국어', value: 'ko-KR' }, { label: '日本語', value: 'ja-JP' }, { label: 'Русский', value: 'ru-RU' }, diff --git a/frontend/src/components/IMChannelPanel.vue b/frontend/src/components/IMChannelPanel.vue index 77e956f8fe0..50fd2396788 100644 --- a/frontend/src/components/IMChannelPanel.vue +++ b/frontend/src/components/IMChannelPanel.vue @@ -685,6 +685,7 @@ const localeOptions = computed(() => ([ { value: '' as IMLocale, label: t('agentEditor.im.replyLanguageDefault') }, { value: 'zh-CN' as IMLocale, label: '简体中文' }, { value: 'en-US' as IMLocale, label: 'English' }, + { value: 'vi-VN' as IMLocale, label: 'Tiếng Việt' }, { value: 'ja-JP' as IMLocale, label: '日本語' }, { value: 'ko-KR' as IMLocale, label: '한국어' }, { value: 'ru-RU' as IMLocale, label: 'Русский' }, diff --git a/frontend/src/i18n/embed.ts b/frontend/src/i18n/embed.ts index 276e4222c2c..57689f6b4cb 100644 --- a/frontend/src/i18n/embed.ts +++ b/frontend/src/i18n/embed.ts @@ -2062,7 +2062,7 @@ const ruEmbedPublish = { }, } as const -export const SUPPORTED_LOCALES = ['zh-CN', 'en-US', 'ko-KR', 'ja-JP', 'ru-RU'] as const +export const SUPPORTED_LOCALES = ['zh-CN', 'en-US', 'ko-KR', 'ja-JP', 'ru-RU', 'vi-VN'] as const export type EmbedLocale = (typeof SUPPORTED_LOCALES)[number] /** Isolated from the main app `locale` key so embed preview never hijacks admin UI language. */ @@ -2076,6 +2076,7 @@ export function normalizeEmbedLocale(raw: string): EmbedLocale { if (s.startsWith('ja')) return 'ja-JP' if (s.startsWith('ru')) return 'ru-RU' if (s.startsWith('zh')) return 'zh-CN' + if (s.startsWith('vi')) return 'vi-VN' const exact = SUPPORTED_LOCALES.find((l) => l.toLowerCase() === s) return exact || 'zh-CN' } @@ -2114,6 +2115,7 @@ export const EMBED_MESSAGES = { 'ko-KR': deepMerge(messages['en-US'], koEmbedPublish), 'ja-JP': messages['ja-JP'], 'ru-RU': deepMerge(messages['en-US'], ruEmbedPublish), + 'vi-VN': messages['en-US'], } as const const i18n = createI18n({ diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts index da377fb00e9..34cba7bff44 100755 --- a/frontend/src/i18n/index.ts +++ b/frontend/src/i18n/index.ts @@ -4,6 +4,7 @@ import ruRU from './locales/ru-RU.ts' import enUS from './locales/en-US.ts' import koKR from './locales/ko-KR.ts' import jaJP from './locales/ja-JP.ts' +import viVN from './locales/vi-VN.ts' import { BUILT_IN_DEFAULT, resolveDefaultLocale } from './resolveDefaultLocale.ts' const messages = { @@ -11,7 +12,8 @@ const messages = { 'en-US': enUS, 'ru-RU': ruRU, 'ko-KR': koKR, - 'ja-JP': jaJP + 'ja-JP': jaJP, + 'vi-VN': viVN } // User's explicit past choice wins; otherwise use the deployment default. diff --git a/frontend/src/i18n/localeKeyAudit.test.ts b/frontend/src/i18n/localeKeyAudit.test.ts index 1be52f30252..9b57aef1adc 100644 --- a/frontend/src/i18n/localeKeyAudit.test.ts +++ b/frontend/src/i18n/localeKeyAudit.test.ts @@ -205,6 +205,7 @@ test('prune rebuild restores registered audit keys from baked-in English default const emptyBundles = { 'en-US': {}, 'zh-CN': {}, + 'vi-VN': {}, 'ko-KR': {}, 'ja-JP': {}, 'ru-RU': {}, diff --git a/frontend/src/i18n/localeKeyAudit.ts b/frontend/src/i18n/localeKeyAudit.ts index c3079374d56..472746d9dd6 100644 --- a/frontend/src/i18n/localeKeyAudit.ts +++ b/frontend/src/i18n/localeKeyAudit.ts @@ -21,10 +21,12 @@ import jaJP from './locales/ja-JP.ts' import koKR from './locales/ko-KR.ts' import ruRU from './locales/ru-RU.ts' import zhCN from './locales/zh-CN.ts' +import viVN from './locales/vi-VN.ts' export const LOCALE_BUNDLES = { 'en-US': enUS, 'zh-CN': zhCN, + 'vi-VN': viVN, 'ko-KR': koKR, 'ja-JP': jaJP, 'ru-RU': ruRU, @@ -527,7 +529,7 @@ export function findAllLocaleMessageCompileErrors( type LocaleTree = Record -const LOCALE_ORDER: LocaleName[] = ['en-US', 'zh-CN', 'ko-KR', 'ru-RU', 'ja-JP'] +const LOCALE_ORDER: LocaleName[] = ['en-US', 'zh-CN', 'vi-VN', 'ko-KR', 'ru-RU', 'ja-JP'] const LOCALES_DIR = join(dirname(fileURLToPath(import.meta.url)), 'locales') function getLocaleValueAtPathParts(current: unknown, parts: string[]): unknown { diff --git a/frontend/src/i18n/locales/en-US.ts b/frontend/src/i18n/locales/en-US.ts index d0c7b4b7d9e..836062f2533 100755 --- a/frontend/src/i18n/locales/en-US.ts +++ b/frontend/src/i18n/locales/en-US.ts @@ -5121,6 +5121,7 @@ export default { language: { zhCN: '简体中文', enUS: 'English', + viVN: 'Tiếng Việt', ruRU: 'Русский', koKR: '한국어', jaJP: '日本語', diff --git a/frontend/src/i18n/locales/vi-VN.ts b/frontend/src/i18n/locales/vi-VN.ts new file mode 100644 index 00000000000..001b504b4e0 --- /dev/null +++ b/frontend/src/i18n/locales/vi-VN.ts @@ -0,0 +1,7819 @@ +export default { + modelCatalog: { + title: 'Model Catalog', + description: 'Model Catalog xác định các mô hình khả dụng khi thêm mới, cùng cấu hình mặc định như Context Window và hỗ trợ suy luận. Thay đổi tại đây áp dụng ngay cho toàn bộ không gian làm việc.', + howItWorks: 'Thứ tự ưu tiên cấu hình', + layers: { + builtin: 'Danh mục tích hợp: Danh sách mô hình mặc định đi kèm mỗi bản phát hành.', + deployment: 'Tệp triển khai: models.json trên máy chủ, ghi đè danh mục tích hợp.', + console: 'Thay đổi từ quản trị viên: Chỉnh sửa tại trang này, ưu tiên cao nhất.', + explicit: 'Cấu hình riêng của không gian làm việc luôn được ưu tiên; thay đổi danh mục không ghi đè mô hình đã lưu.' + }, + add: 'Thêm mô hình', + more: 'Thêm', + jsonEditor: 'Sửa JSON', + history: 'Lịch sử phiên bản', + import: 'Nhập JSON', + export: 'Xuất thay đổi', + search: 'Tìm theo ID hoặc tên mô hình', + allProviders: 'Tất cả nhà cung cấp', + allTypes: 'Tất cả loại', + onlyModified: 'Chỉ mục đã sửa', + summary: '{count} mô hình · phiên bản {version}', + columns: { + model: 'Mô hình', + provider: 'Nhà cung cấp', + type: 'Loại', + tokens: 'Ngữ cảnh / đầu ra', + capabilities: 'Khả năng', + source: 'Nguồn' + }, + capability: { + reasoning: 'Suy luận', + image: 'Hình ảnh', + audio: 'Âm thanh', + video: 'Video' + }, + source: { + builtin: 'Tích hợp', + deployment: 'Triển khai', + console: 'Quản trị viên' + }, + rule: 'Mẫu quy tắc', + ruleTip: 'Khớp nhóm mô hình theo tên và gán giá trị mặc định. Không hiển thị trong bộ chọn mô hình.', + hidden: 'Đã ẩn', + edit: 'Sửa', + view: 'Xem', + empty: 'Không tìm thấy mô hình phù hợp', + editDescription: '{provider} · {type}', + ruleNotice: 'Mẫu này áp dụng mặc định cho các mô hình có tên trùng khớp. Để thay đổi, chọn Thêm → Sửa JSON.', + fieldsSection: 'Mặc định', + nameDesc: 'Tên hiển thị trong bộ chọn mô hình.', + dimension: 'Số chiều vector', + dimensionDesc: 'Tự động điền khi thêm mô hình embedding; phải khớp với giá trị mô hình trả về thực tế.', + inputDesc: 'Loại dữ liệu đầu vào được hỗ trợ. Mô hình hỗ trợ hình ảnh có thể dùng làm mô hình thị giác.', + thinkingLevels: 'Mức độ suy luận', + thinkingLevelsDesc: 'Cường độ suy luận khi trò chuyện. Nếu không chọn \'Tắt\', mô hình sẽ luôn suy luận.', + levelsNeedReasoning: 'Bật Suy luận để tùy chỉnh mức độ.', + levelsUnsupported: 'API của nhà cung cấp này không hỗ trợ phân cấp mức độ suy luận.', + textOnly: 'Chỉ văn bản', + noLevels: 'Không có', + sourceLink: 'Tài liệu nhà cung cấp', + customHint: 'Mô hình này do quản trị viên thêm trực tiếp tại đây; mọi giá trị đều lấy từ trang này.', + fieldsHint: 'Cấu hình riêng của không gian làm việc vẫn được ưu tiên. Xóa trường để khôi phục mặc định.', + context: 'Context Window', + contextDesc: 'Số token tối đa mô hình có thể xử lý trong một lượt.', + output: 'Đầu ra tối đa', + outputDesc: 'Số token tối đa tạo ra trong một phản hồi.', + reasoning: 'Suy luận', + reasoningDesc: 'Cho phép mô hình xuất nội dung suy luận.', + hide: 'Ẩn khỏi bộ chọn', + hideDesc: 'Mô hình bị ẩn sẽ không hiển thị khi thêm mới. Các mô hình hiện có không bị ảnh hưởng.', + inputModes: 'Phương thức đầu vào', + inherited: 'Mặc định: {value}', + notSet: 'Chưa đặt', + optional: 'Không bắt buộc', + yes: 'Có', + no: 'Không', + modified: 'Đã sửa', + layersSection: 'Giá trị theo lớp cấu hình', + layerField: 'Cài đặt', + layerBuiltin: 'Tích hợp', + layerDeployment: 'Triển khai', + layerEffective: 'Đang áp dụng', + save: 'Lưu và áp dụng', + restore: 'Khôi phục mặc định', + restoreConfirm: 'Xóa toàn bộ thay đổi của quản trị viên cho mô hình này và áp dụng ngay lập tức?', + restored: 'Đã khôi phục. Các phiên bản khác sẽ đồng bộ sau khoảng 5 giây.', + remove: 'Xóa mô hình', + removeConfirm: 'Xóa mô hình do quản trị viên thêm này khỏi danh mục và áp dụng ngay lập tức?', + removed: 'Đã xóa. Các phiên bản khác sẽ đồng bộ sau khoảng 5 giây.', + published: 'Đã áp dụng. Các phiên bản khác sẽ đồng bộ sau khoảng 5 giây.', + conflict: 'Quản trị viên khác vừa cập nhật danh mục. Trang đã được làm mới; vui lòng thử lại.', + loadFailed: 'Không thể tải Model Catalog', + deploymentError: 'Không thể tải models.json từ tệp triển khai; đang sử dụng danh mục tích hợp: {error}', + syncError: 'Không thể đồng bộ phiên bản mới nhất; trang có thể chưa hiển thị cấu hình đang áp dụng: {error}', + addDescription: 'Thêm mô hình chưa có trong danh mục để chọn trực tiếp trong cài đặt mô hình.', + modelId: 'ID mô hình', + modelIdPlaceholder: 'Tên mô hình theo API của nhà cung cấp, ví dụ: gpt-5-mini', + displayName: 'Tên hiển thị', + required: 'Vui lòng chọn nhà cung cấp và nhập ID mô hình', + exists: 'Mô hình này đã có trong danh mục; vui lòng chỉnh sửa thay vì thêm mới', + jsonDescription: 'Chỉnh sửa tất cả thay đổi của quản trị viên dưới dạng models.json. Thích hợp để sửa hàng loạt hoặc di chuyển dữ liệu.', + jsonHint: 'Chỉ đưa vào các trường cần thay đổi; xóa trường để khôi phục mặc định. Quản lý thông tin xác thực, header và biến môi trường trong cài đặt mô hình hoặc tệp triển khai. Biểu tượng phải là SVG nội dòng. Tối đa 1 MiB.', + jsonClear: 'Xóa toàn bộ thay đổi', + jsonCheck: 'Kiểm tra thay đổi', + jsonPublish: 'Áp dụng {count} thay đổi', + jsonUnchanged: 'Trùng khớp với cấu hình đang áp dụng; không có thay đổi nào.', + changesTitle: 'Thay đổi sẽ áp dụng', + change: { + added: 'Đã thêm', + removed: 'Đã xóa', + updated: 'Đã thay đổi', + provider: 'Nhà cung cấp' + }, + publishHint: 'Áp dụng ngay trên phiên bản này; các phiên bản khác sẽ đồng bộ sau khoảng 5 giây.', + invalid: 'Nhập tài liệu models.json có chứa đối tượng providers.', + tooLarge: 'Tệp không được vượt quá 1 MiB.', + historyDescription: 'Lưu 20 phiên bản gần nhất. Khôi phục một phiên bản sẽ áp dụng ngay lập tức.', + historyVersion: 'Phiên bản {version}', + historyCurrent: 'Hiện tại', + historyRestore: 'Khôi phục', + historyRestoreConfirm: 'Khôi phục phiên bản {version} và áp dụng ngay cho tất cả không gian làm việc?', + historyEmpty: 'Không có phiên bản trước đó', + historyModels: '{count} mô hình đã thay đổi', + historyNoOverrides: 'Không có thay đổi từ quản trị viên' + }, + toolbox: { + title: 'Hộp công cụ', + description: 'Quản lý kỹ năng, công cụ bên ngoài và kết nối trình duyệt cho agent.', + unavailable: 'Không có công cụ nào trong không gian làm việc hiện tại.' + }, + localBrowser: { + pipOpen: 'Mở cửa sổ nổi', + pipReturn: 'Quay lại hội thoại', + pipFailed: 'Không thể mở cửa sổ nổi. Vui lòng thử lại.', + captureScreenshot: 'Chụp màn hình', + navigationIncomplete: 'Điều hướng chưa đạt giai đoạn tải yêu cầu. Vui lòng kiểm tra trang hiện tại.', + noEntries: 'Không có mục nào được trả về.', + stopping: 'Đang kết thúc tác vụ…', + elapsedSeconds: '{seconds} giây', + searchInstructionsTitle: 'Hướng dẫn tìm kiếm bằng trình duyệt', + searchInstructionsDescription: 'Đặt công cụ tìm kiếm và URL tìm kiếm ưu tiên.', + searchInstructionsHint: 'Áp dụng cho yêu cầu tiếp theo. Để trống để dùng mặc định.', + searchInstructionsReset: 'Khôi phục mặc định', + searchInstructionsSaved: 'Đã lưu', + sourceHint: 'Dùng trình duyệt cục bộ để tra cứu và tương tác với trang trong lượt này, song song với tìm kiếm web, kho tri thức và các công cụ khác.', + pressKey: 'Nhấn phím', + hoverPage: 'Rê chuột lên phần tử', + scrollPage: 'Cuộn trang', + focusElement: 'Focus phần tử', + blurElement: 'Bỏ focus', + selectOption: 'Chọn tùy chọn', + closeTab: 'Đóng tab', + runScript: 'Chạy tập lệnh trang', + readConsole: 'Đọc console', + readNetwork: 'Kiểm tra yêu cầu mạng', + resizeWindow: 'Đổi kích thước cửa sổ', + emulateDevice: 'Giả lập thiết bị', + actionPending: 'Đang thao tác trình duyệt…', + actionRecorded: 'Đã ghi nhận thao tác trình duyệt', + untitledTab: 'Tab không có tiêu đề', + contentTruncated: 'Chỉ hiển thị một phần nội dung trang.', + controlScope: 'Chỉ điều khiển trình duyệt của cuộc trò chuyện này', + pauseHint: 'Tạm dừng thao tác trình duyệt và giữ nguyên các trang để tiếp tục sau. Cuộc trò chuyện vẫn tiếp diễn.', + stopHint: 'Đóng các tab do tác vụ này tạo và trả lại các tab đã mượn. Giữ trình duyệt mở và ghép nối.', + openPage: 'Mở trang', + switchPage: 'Chuyển trang', + readPage: 'Đọc trang', + listTabs: 'Danh sách tab', + clickPage: 'Nhấp phần tử', + fillPage: 'Điền nội dung', + waitPage: 'Chờ trang', + openTab: 'Tạo tab tác vụ', + switchTab: 'Chuyển tab tác vụ', + authorizeTab: 'Yêu cầu quyền truy cập tab', + returnTab: 'Trả lại tab', + needHelp: 'Cần bạn xử lý', + browserAction: 'Thao tác trình duyệt', + actionFailed: 'Chưa hoàn thành', + actionCompleted: 'Thao tác hoàn tất', + commandBusy: 'Lệnh trình duyệt trước đó vẫn đang chạy. Vui lòng chờ.', + invalidArguments: 'Tham số công cụ trình duyệt không hợp lệ hoặc thiếu. Agent cần sửa lại trước khi tiếp tục.', + commandInterrupted: 'Thao tác trình duyệt bị gián đoạn. Kiểm tra trang trước khi tiếp tục từ bản xem trước.', + actionFailedHint: 'Thao tác trình duyệt chưa hoàn tất. Kiểm tra trang và thử lại.', + previewStale: 'Bản xem trước chưa cập nhật', + previewIdle: 'Đang giữ bản xem trước gần nhất', + previewLive: 'Đang đồng bộ bản xem trước', + previewLoading: 'Đang tải bản xem trước', + borrowHint: 'Chuyển sang trang đang mượn và chọn Cho phép hoặc Từ chối trong xác nhận BrowserSkill. Quá trình sẽ tự động tiếp tục khi được phê duyệt. Nút tiếp tục chỉ khôi phục tác vụ tạm dừng, không phê duyệt mượn tab.', + helpHint: 'Mở trình duyệt từ bản xem trước, hoàn thành thao tác được yêu cầu, sau đó xác nhận xong trên lớp phủ trợ giúp của trình duyệt.', + settingsTitle: 'Kết nối trình duyệt', + settingsDescription: 'Ghép nối BrowserSkill với Chrome hoặc Edge cục bộ để thao tác trên các trang web thật từ cuộc trò chuyện.', + openSettings: 'Mở cài đặt trình duyệt', + settingsHint: 'Kết nối BrowserSkill trong Hộp công cụ để sử dụng trình duyệt cục bộ tại đây.', + unavailable: 'Duyệt web cục bộ chưa được bật trên máy chủ này. Liên hệ quản trị viên.', + source: 'Nguồn trình duyệt', + sandbox: 'Trình duyệt Sandbox', + local: 'Trình duyệt cục bộ', + paused: 'Đã tạm dừng', + connected: 'Đã kết nối', + disconnected: 'Đã ngắt kết nối', + resume: 'Tiếp tục trình duyệt', + pause: 'Tạm dừng trình duyệt', + start: 'Bắt đầu tác vụ', + stop: 'Kết thúc tác vụ trình duyệt', + resumeShort: 'Tiếp tục', + pauseShort: 'Tạm dừng', + stopShort: 'Kết thúc', + pairHint: 'Mở Cài đặt kết nối → Kết nối từ xa trong tiện ích mở rộng, dán liên kết ghép nối và xác nhận máy chủ. Liên kết có hiệu lực trong 5 phút và chỉ dùng một lần.', + copyPairing: 'Sao chép liên kết ghép nối', + copied: 'Đã sao chép', + windowHint: 'Tác vụ chạy trong Cửa sổ Agent riêng biệt. Cần sự cho phép của bạn để mượn các tab hiện có.', + preview: 'Xem trước tác vụ trình duyệt cục bộ', + waiting: 'Đang chờ trang tác vụ', + startHint: 'Yêu cầu trình duyệt sẽ tạo một Cửa sổ Agent riêng.', + revoke: 'Thu hồi quyền thiết bị', + revokeConfirm: 'Bạn cần ghép nối lại trước khi sử dụng trình duyệt cục bộ.', + failed: 'Thao tác thất bại. Vui lòng thử lại.', + productDescription: 'Tiện ích mở rộng mã nguồn mở cho Chrome và Edge cho phép agent mở trang web, đọc nội dung và thao tác trên trình duyệt của bạn.', + offline: 'Ngoại tuyến', + notPaired: 'Chưa ghép nối', + lastSeen: 'Kết nối lần cuối', + readyHint: 'Đã sẵn sàng. Quay lại cuộc trò chuyện và mô tả tác vụ trình duyệt cần thực hiện.', + capabilitiesTitle: 'Agent của bạn có thể', + sidebarStatus: 'Hiện trạng thái kết nối trên thanh bên', + reconnectHint: 'Đã lưu xác thực. Giữ trình duyệt và BrowserSkill luôn mở để tự động kết nối lại.', + replaceDevice: 'Đổi trình duyệt', + installExtension: 'Cài đặt BrowserSkill', + storeInstall: 'Cửa hàng Chrome trực tuyến', + edgeStoreInstall: 'Edge Add-ons', + extensionMinVersion: 'Yêu cầu BrowserSkill v{version} trở lên. Tương thích Chrome và Edge.', + extensionOutdated: 'Tiện ích v{current} đã cũ. Hãy cập nhật lên v{version} trở lên.', + manualInstall: 'Cài đặt thủ công (dự phòng)', + storeInstallHint: 'Cài đặt BrowserSkill từ Cửa hàng Chrome trực tuyến hoặc Edge Add-ons, sau đó quay lại đây ghép nối.', + installHint: 'Nếu cửa hàng không khả dụng hoặc phiên bản không tương thích, hãy tải gói cài đặt phù hợp và cài thủ công.', + downloadExtension: 'Tải gói cài đặt tương thích', + officialExtension: 'Tiện ích chính thức (Cửa hàng Chrome)', + installGuide: 'Cách cài đặt gói đã tải về?', + pairGuide: 'Cách sử dụng liên kết ghép nối?', + pairBrowser: 'Kết nối trình duyệt này', + packageUnavailable: 'Vui lòng liên hệ quản trị viên để lấy gói tiện ích tương thích; chưa cấu hình liên kết tải xuống.', + manualCopy: 'Chọn và sao chép liên kết bên dưới. Liên kết hết hạn sau 5 phút và chỉ dùng một lần.', + pairingReady: 'Đã sao chép liên kết. Dán vào tiện ích trong vòng 5 phút. Chỉ sử dụng một lần.', + copyAgain: 'Sao chép lại', + usageTitle: 'Hướng dẫn sử dụng', + usageStep1Title: 'Cài đặt tiện ích', + usageStep1Text: 'Giải nén tệp ZIP đã tải, nhập chrome://extensions (edge://extensions trên Edge) vào thanh địa chỉ, bật Chế độ nhà phát triển, chọn Tải tiện ích đã giải nén và chọn thư mục tiện ích vừa giải nén.', + usageStep2Title: 'Ghép nối trình duyệt này', + usageStep2Text: 'Sao chép liên kết ghép nối vào Cài đặt kết nối → Kết nối từ xa trong tiện ích và xác nhận máy chủ. Chỉ cần ghép nối một lần cho tất cả cuộc trò chuyện trong không gian này.', + usageStep3Title: 'Mô tả tác vụ trong đoạn chat', + usageStep3Text: 'Bật Trình duyệt cục bộ trên thanh nhập tin nhắn trước khi gửi tác vụ web. Ghép nối sẽ không tự động bật tùy chọn này. Tác vụ chạy trong một Cửa sổ Agent riêng biệt.', + usageStep4Title: 'Xem trước, định vị và tiếp tục', + usageStep4Text: 'Khung xem trước nhỏ sẽ xuất hiện trong cuộc trò chuyện. Nhấp vào để tìm tab tác vụ. Tác vụ gián đoạn sẽ tạm dừng khi kết nối lại — tiếp tục từ khung xem trước. Các tab hiện có cần được bạn cấp quyền.', + running: 'Đang chạy', + locateWindow: 'Hiện trình duyệt', + reconnectShort: 'Đang chờ kết nối lại' + }, + artifactLibrary: { + title: 'Artifacts', + subtitle: 'Các tệp do agent tạo trong tất cả cuộc trò chuyện của bạn', + typeFilter: 'Lọc theo loại', + searchPlaceholder: 'Tìm kiếm tên tệp', + categories: { + all: 'Tất cả', + document: 'Tài liệu', + spreadsheet: 'Bảng tính', + presentation: 'Bản trình bày', + image: 'Hình ảnh', + web: 'Trang web', + data: 'Dữ liệu' + }, + groups: { + today: 'Hôm nay', + yesterday: 'Hôm qua', + last7Days: '7 ngày qua', + last30Days: '30 ngày qua', + earlier: 'Trước đó' + }, + total: '{count} tệp', + versions: '{count} phiên bản', + preview: 'Xem trước', + delete: 'Xóa', + deleteTitle: 'Xóa tệp này?', + deleteConfirm: '“{name}” và dữ liệu lưu trữ sẽ bị xóa vĩnh viễn. Không thể hoàn tác.', + deleteConfirmVersions: 'Toàn bộ {count} phiên bản của “{name}” và dữ liệu lưu trữ sẽ bị xóa vĩnh viễn. Không thể hoàn tác.', + deleted: 'Đã xóa tệp', + deleteFailed: 'Xóa thất bại, vui lòng thử lại.', + download: 'Tải xuống', + downloadFailed: 'Tải xuống thất bại. Vui lòng thử lại sau.', + openSession: 'Mở cuộc trò chuyện', + untitledSession: 'Cuộc trò chuyện chưa có tên', + loadMore: 'Tải thêm', + loadFailed: 'Không thể tải Artifacts', + retry: 'Thử lại', + clearFilters: 'Xóa bộ lọc', + empty: { + title: 'Chưa có Artifacts nào', + description: 'Yêu cầu agent tạo báo cáo, bảng tính hoặc slide và tệp sẽ xuất hiện ở đây' + }, + noMatches: { + title: 'Không tìm thấy tệp phù hợp', + description: 'Thử tìm bằng từ khóa hoặc loại tệp khác' + } + }, + resourceSort: { + title: 'Sắp xếp', + updatedTime: 'Thời gian cập nhật', + updatedTimeDescription: 'Tùy chọn mặc định.', + createdTime: 'Thời gian tạo', + createdTimeDescription: 'Xem các mục mới nhất hoặc cũ nhất', + name: 'Tên', + nameDescription: 'Tìm nhanh khi đã biết tên mục', + recentlyUpdated: 'Cập nhật gần đây', + earliestUpdated: 'Cập nhật cũ nhất', + recentlyCreated: 'Mới tạo gần đây', + earliestCreated: 'Tạo cũ nhất', + nameAscending: 'A–Z', + nameDescending: 'Z–A' + }, + menu: { + sessionInProgress: 'Cuộc trò chuyện đang diễn ra', + knowledgeBase: 'Kho tri thức', + agents: 'Agent', + artifacts: 'Artifacts', + organizations: 'Không gian chung', + newChat: 'Đoạn chat mới', + settings: 'Cài đặt hệ thống', + logout: 'Đăng xuất', + clearMessages: 'Xóa tin nhắn', + clearMessagesSuccess: 'Đã xóa tin nhắn', + clearMessagesFailed: 'Xoá tin nhắn thất bại, vui lòng thử lại sau', + renameSession: 'Đổi tên', + renameSessionSuccess: 'Đã cập nhật tiêu đề', + renameSessionFailed: 'Cập nhật tiêu đề thất bại, vui lòng thử lại sau', + batchManage: 'Quản lý hàng loạt', + newSession: 'Đoạn chat mới', + pin: 'Ghim', + unpin: 'Bỏ ghim', + pinFailed: 'Ghim thất bại, vui lòng thử lại sau', + unpinFailed: 'Bỏ ghim thất bại, vui lòng thử lại sau', + search: 'Tìm kiếm', + collapseSidebar: 'Thu gọn thanh bên', + expandSidebar: 'Mở rộng thanh bên', + logoutSuccess: 'Đăng xuất thành công', + myChats: 'Hội thoại của tôi', + apiChats: 'Phiên API', + noSessions: 'Chưa có cuộc trò chuyện nào' + }, + chatHeader: { + moreActions: 'Thao tác khác', + toggleSandboxPanel: 'Terminal Sandbox', + copySessionId: 'Sao chép ID phiên', + copyLink: 'Sao chép liên kết hội thoại', + copyMarkdown: 'Sao chép dạng Markdown', + openNewWindow: 'Mở trong cửa sổ mới', + deleteSession: 'Xoá cuộc trò chuyện', + renamePlaceholder: 'Nhập tiêu đề cuộc trò chuyện', + unpinSuccess: 'Đã bỏ ghim cuộc trò chuyện', + temporaryWorkspace: 'Không gian làm việc tạm thời', + sessionIdCopied: 'Đã sao chép ID phiên', + linkCopied: 'Đã sao chép liên kết hội thoại', + copyFailed: 'Sao chép thất bại. Vui lòng kiểm tra quyền truy cập bảng tạm của trình duyệt.', + markdownCopied: 'Đã sao chép toàn bộ hội thoại dạng Markdown', + markdownCopyFailed: 'Sao chép Markdown thất bại. Vui lòng thử lại.', + clearConfirmTitle: 'Xoá tin nhắn hội thoại', + clearConfirmBody: 'Xoá tất cả tin nhắn trong cuộc trò chuyện này? Cuộc trò chuyện vẫn được giữ lại nhưng hành động này không thể hoàn tác.', + deleteConfirmTitle: 'Xoá cuộc trò chuyện', + deleteConfirmBody: 'Xoá cuộc trò chuyện này? Hành động này không thể hoàn tác.', + deleteSuccess: 'Đã xoá cuộc trò chuyện', + markdown: { + sessionId: 'ID phiên', + exportedAt: 'Thời gian xuất', + user: 'Người dùng', + assistant: 'Trợ lý', + attachments: 'Tệp đính kèm', + references: 'Nguồn tham khảo' + } + }, + newUserGuide: { + stepOf: '{current} / {total}', + skip: 'Bỏ qua', + prev: 'Quay lại', + next: 'Tiếp tục', + done: 'Hoàn tất', + reopen: 'Hướng dẫn sử dụng', + steps: { + welcome: { + title: 'Chào mừng đến với WeKnora', + desc: 'Vài bước nhanh giúp bạn làm quen với kho tri thức, hội thoại và agent. Nhấn "Tiếp tục" để bắt đầu.' + }, + knowledge: { + title: 'Tạo kho tri thức', + desc: 'Mọi thứ bắt đầu từ đây: tải lên tài liệu, trang web hoặc FAQ để WeKnora tự động phân tích và lập chỉ mục. Nhấn vào đây để mở kho tri thức.' + }, + chat: { + title: 'Bắt đầu chat với AI', + desc: 'Đặt câu hỏi dựa trên kho tri thức và nhận câu trả lời chính xác có trích dẫn nguồn. Nhấn vào đây để bắt đầu đoạn chat mới.' + }, + agents: { + title: 'Xây dựng agent chuyên biệt', + desc: 'Kết hợp kho tri thức, prompt và công cụ thành các agent tái sử dụng, đáp ứng chính xác nhu cầu chuyên môn.' + }, + settings: { + title: 'Tài khoản & cài đặt', + desc: 'Mở mục này để quản lý tài khoản, thành viên và cài đặt hệ thống. Bạn có thể mở lại hướng dẫn từ nút trợ giúp cạnh tên tài khoản.' + }, + models: { + title: 'Cấu hình mô hình', + desc: 'Bước quan trọng: thêm mô hình chat, embedding và các mô hình khác trong Quản lý mô hình để kho tri thức và hội thoại hoạt động. Nhấn "Thêm mô hình" để bắt đầu.' + }, + done: { + title: 'Bạn đã sẵn sàng', + desc: 'Bạn đã nắm được các tính năng cốt lõi — hãy bắt đầu xây dựng trợ lý tri thức! Xem lại hướng dẫn bất cứ lúc nào từ nút trợ giúp cạnh tên tài khoản.' + } + } + }, + contextualGuide: { + stepOf: '{current} / {total}', + skip: 'Bỏ qua', + prev: 'Quay lại', + next: 'Tiếp tục', + done: 'Đã hiểu', + interactHint: 'Nhấn vào vùng được đánh dấu để tiếp tục', + kbList: { + steps: { + create: { + title: 'Tạo kho tri thức đầu tiên', + desc: 'Kho tri thức chứa tài liệu và FAQ. Nhấn nút "Kho tri thức mới" được đánh dấu bên dưới để bắt đầu thiết lập.' + } + } + }, + tenantModels: { + needChatModelFirst: 'Vui lòng thêm mô hình chat (KnowledgeQA) trước khi tạo agent.', + steps: { + intro: { + title: 'Cấu hình mô hình trước', + desc: 'Kho tri thức tài liệu cần ít nhất một mô hình chat (tóm tắt & hỏi đáp) và một mô hình Embedding (tìm kiếm vector). Hãy thêm chúng trong cài đặt hệ thống.' + }, + addModel: { + title: 'Thêm mô hình', + desc: 'Nhấn "Thêm mô hình" và cấu hình loại KnowledgeQA (chat) và Embedding. Người dùng Lite có thể tải mô hình cục bộ qua Ollama.' + }, + done: { + title: 'Sau đó tiếp tục', + desc: 'Sau khi lưu mô hình, đóng cài đặt và nhấn "Kho tri thức mới". Trình hướng dẫn sẽ giúp bạn thiết lập loại, lập chỉ mục và liên kết mô hình.' + } + }, + stepsAgent: { + intro: { + title: 'Cấu hình mô hình chat trước', + desc: 'Tạo agent cần ít nhất một mô hình KnowledgeQA. Hãy thêm trong cài đặt hệ thống (Embedding chỉ bắt buộc cho kho tri thức).' + }, + addModel: { + title: 'Thêm mô hình chat', + desc: 'Nhấn "Thêm mô hình" và cấu hình loại KnowledgeQA.' + }, + done: { + title: 'Sau đó tạo agent', + desc: 'Sau khi lưu, đóng cài đặt và nhấn "Tạo agent". Trình hướng dẫn sẽ hỗ trợ bạn thiết lập chế độ, kho tri thức và tuỳ chọn tệp đính kèm.' + } + } + }, + kbCreate: { + steps: { + type: { + title: 'Chọn loại kho tri thức', + desc: 'Kho tài liệu dành cho tệp PDF, Word,... Kho FAQ dành cho các cặp hỏi - đáp. Không thể thay đổi loại sau khi tạo.' + }, + name: { + title: 'Đặt tên', + desc: 'Chọn tên rõ ràng như "Tài liệu sản phẩm" hoặc "FAQ hỗ trợ". Mô tả là tuỳ chọn.' + }, + indexing: { + title: 'Khả năng lập chỉ mục', + desc: 'Tìm kiếm vector và từ khoá được bật mặc định. Bạn cũng có thể bật lập chỉ mục Wiki hoặc đồ thị tri thức. Hãy duy trì ít nhất một chế độ tìm kiếm.' + }, + navModels: { + title: 'Thiết lập mô hình (bắt buộc)', + desc: 'Mỗi kho tri thức cần một mô hình chat; tính năng truy xuất cũng cần mô hình Embedding. Mở "Cấu hình mô hình" ở thanh bên trái.' + }, + llm: { + title: 'Mô hình chat / tóm tắt', + desc: 'Dùng để tóm tắt và trả lời câu hỏi. Nếu danh sách trống, hãy dùng menu thả xuống để mở cài đặt và thêm mô hình.' + }, + embedding: { + title: 'Mô hình Embedding', + desc: 'Chuyển văn bản thành vector để tìm kiếm ngữ nghĩa. Hoạt động song song với lập chỉ mục vector/từ khoá ở trên.' + }, + parser: { + title: 'Bộ phân tích cú pháp (tuỳ chọn)', + desc: 'Cách phân tích tệp PDF và Office. Cấu hình mặc định phù hợp với hầu hết tài liệu; điều chỉnh nếu cần OCR hoặc xử lý bố cục đặc thù.' + }, + chunking: { + title: 'Chunk (tuỳ chọn)', + desc: 'Cách chia nhỏ tài liệu để truy xuất. Kích thước Chunk mặc định đã được tối ưu cho RAG và hiếm khi cần thay đổi.' + }, + storage: { + title: 'Bộ lưu trữ (tùy chọn)', + desc: 'Nơi lưu tệp gốc (cục bộ hoặc object storage). Thường dùng mặc định của không gian làm việc.' + }, + navMultimodal: { + title: 'Đa phương thức / hình ảnh (tùy chọn)', + desc: 'Bật nếu tài liệu chứa biểu đồ, bản quét hoặc nhiều hình ảnh cần phân tích thị giác.' + }, + multimodalToggle: { + title: 'Bật phân tích đa phương thức', + desc: 'Khi bật, tài liệu chứa hình ảnh sẽ được xử lý bằng mô hình VLM để tối ưu hóa truy xuất.' + }, + multimodalVllm: { + title: 'Chọn mô hình VLM', + desc: 'Tính năng đa phương thức yêu cầu VLM. Hãy thêm mô hình trong cài đặt hệ thống nếu danh sách trống.' + }, + faq: { + title: 'Lập chỉ mục FAQ', + desc: 'Chọn cách lập chỉ mục các cặp hỏi-đáp. Bạn có thể thêm FAQ sau khi tạo.' + }, + submit: { + title: 'Tạo kho tri thức', + desc: 'Nhấn Đã hiểu để đóng hướng dẫn mà không tạo. Khi sẵn sàng, hãy nhập tên, xác nhận loại và mô hình, rồi nhấn Tạo.' + } + } + }, + agentList: { + steps: { + create: { + title: 'Tạo agent', + desc: 'Agent kết hợp mô hình, kho tri thức, công cụ và câu lệnh thành trợ lý dùng lại được. Nhấn nút "Tạo agent".' + } + } + }, + agentCreate: { + steps: { + mode: { + title: 'Chọn chế độ chạy', + desc: '"Trả lời nhanh" cho hỏi đáp trực tiếp; "Suy luận thông minh" sử dụng công cụ và tư duy đa bước cho tác vụ phức tạp.' + }, + agentType: { + title: 'Chọn loại agent', + desc: 'Mẫu tạo sẵn sẽ điền trước prompt hệ thống, công cụ và phạm vi tri thức. Tên và mô tả sẽ tự cập nhật theo mẫu.' + }, + name: { + title: 'Tên và mô tả', + desc: 'Đặt tên dễ nhận biết. Chế độ suy luận thông minh có thể điền trước tên mặc định để bạn chỉnh sửa.' + }, + navModel: { + title: 'Gán mô hình trò chuyện', + desc: 'Mỗi agent cần một mô hình KnowledgeQA làm công cụ suy luận.' + }, + model: { + title: 'Chọn mô hình', + desc: 'Chọn từ danh sách mô hình đã cấu hình, hoặc thêm mô hình mới trong cài đặt hệ thống.' + }, + navKnowledge: { + title: 'Liên kết kho tri thức', + desc: 'Giới hạn phạm vi tri thức agent có thể truy xuất. Mặc định là tất cả kho tri thức.' + }, + knowledge: { + title: 'Phạm vi tri thức', + desc: '"Tất cả" cho trợ lý chung; "Đã chọn" cho chuyên biệt; "Không" chỉ dựa vào mô hình hoặc tìm kiếm web.' + }, + navWebsearch: { + title: 'Tìm kiếm web (tùy chọn)', + desc: 'Cho phép agent tìm kiếm trực tuyến để cập nhật thông tin mới nhất.' + }, + navMultimodal: { + title: 'Tải tệp đính kèm (tùy chọn)', + desc: 'Cho phép gửi hình ảnh, tài liệu và âm thanh trong đoạn chat; phân tích ảnh cần VLM trong cài đặt hệ thống.' + }, + multimodal: { + title: 'Bật tải tệp đính kèm', + desc: 'Cấu hình tải ảnh, âm thanh và quy tắc phân tích tệp; chọn VLM bên dưới khi bật tải ảnh.' + }, + navTools: { + title: 'Công cụ & MCP (tùy chọn)', + desc: 'Ở chế độ suy luận thông minh, bật công cụ tích hợp và dịch vụ MCP để tìm kiếm, xử lý mã nguồn và hơn thế nữa.' + }, + submit: { + title: 'Lưu agent', + desc: 'Nhấn nút xác nhận để hoàn tất. Sau đó bạn có thể chọn agent này khi trò chuyện.' + } + } + }, + kbDetail: { + steps: { + intro: { + title: 'Kho tri thức đang trống', + desc: 'Thêm tài liệu đầu tiên để bắt đầu tìm kiếm và trò chuyện. Bạn cũng có thể kéo thả các tệp được hỗ trợ.' + }, + upload: { + title: 'Thêm tài liệu', + desc: 'Dùng menu này để tải tệp/thư mục, nhập từ URL hoặc tạo nội dung trực tuyến.' + }, + done: { + title: 'Sẵn sàng sau khi phân tích', + desc: 'Khi tài liệu đã lập chỉ mục xong, hãy nhắc tên kho tri thức bằng {\'@\'} trong chat để nhận câu trả lời kèm trích dẫn.' + } + } + }, + chat: { + steps: { + kb: { + title: 'Chọn phạm vi tri thức', + desc: 'Nhấn {\'@\'} để chọn kho tri thức hoặc tệp cụ thể. Câu trả lời sẽ chỉ dùng nội dung đã chọn; nếu không sẽ theo cài đặt của agent.' + }, + input: { + title: 'Nhập câu hỏi', + desc: 'Mô tả nội dung bạn cần hỏi, hoặc nhấn vào câu hỏi gợi ý phía trên để bắt đầu nhanh.' + }, + send: { + title: 'Gửi để bắt đầu chat', + desc: 'Tin nhắn gửi đi sẽ mở một phiên mới. AI sẽ trả lời dựa trên kho tri thức kèm Chunk dẫn nguồn.' + }, + done: { + title: 'Sẵn sàng trải nghiệm', + desc: 'Thử đặt câu hỏi liên quan đến tài liệu đã tải lên để xem câu trả lời kèm nguồn dẫn chứng.' + } + } + } + }, + batchManage: { + selectAll: 'Chọn tất cả', + cancel: 'Hủy', + delete: 'Xóa cuộc trò chuyện', + deleteConfirmTitle: 'Xóa cuộc trò chuyện', + deleteConfirmBody: 'Bạn có chắc chắn muốn xóa {count} cuộc trò chuyện đã chọn? Hành động này không thể hoàn tác.', + deleteAllConfirmBody: 'Bạn có chắc chắn muốn xóa tất cả cuộc trò chuyện? Hành động này không thể hoàn tác.', + deleteSuccess: 'Xóa thành công', + deleteFailed: 'Xóa thất bại, vui lòng thử lại sau' + }, + listSpaceSidebar: { + all: 'Tất cả', + workspace: 'Không gian làm việc', + spaces: 'Được chia sẻ với tôi', + favorites: 'Đã gắn sao', + recents: 'Gần đây' + }, + resourceOrigin: { + mine: 'Của tôi', + mineTooltip: 'Do bạn tạo', + tenant: 'Không gian làm việc', + tenantTooltip: 'Do thành viên khác trong không gian làm việc tạo', + tenantTooltipWithCreator: 'Được tạo bởi {creator}', + space: 'Không gian', + spaceTooltip: 'Được chia sẻ qua không gian "{space}"', + spaceTooltipWithTenant: 'Được chia sẻ qua không gian "{space}" · từ {tenant}', + shared: 'Bên ngoài', + sharedTooltip: 'Truy cập từ không gian làm việc bên ngoài qua không gian chia sẻ' + }, + knowledgeBase: { + tagAddAction: 'Thêm thẻ', + documentCount: '{count} tài liệu', + filters: 'Bộ lọc', + clearFilters: 'Xóa bộ lọc', + title: 'Kho tri thức', + fileContent: 'Nội dung tệp', + accessInfo: { + myRole: 'Vai trò của tôi', + roleOwner: 'Chủ sở hữu', + permissionOwner: 'Chỉnh sửa, quản lý cài đặt, xóa kho tri thức', + permissionAdmin: 'Chỉnh sửa, quản lý chia sẻ', + permissionEditor: 'Chỉnh sửa tài liệu và thẻ', + permissionViewer: 'Chỉ xem và tìm kiếm', + fromOrg: 'Từ không gian', + sharedAt: 'Được chia sẻ lúc', + lastUpdated: 'Cập nhật lần cuối' + }, + infoCard: { + tooltip: 'Xem thông tin kho tri thức', + title: 'Thông tin kho tri thức', + basic: 'Cơ bản', + access: 'Quyền truy cập', + binding: 'Bộ lưu trữ liên kết', + capabilities: 'Khả năng hỗ trợ', + stats: 'Thống kê', + type: 'Loại', + createdAt: 'Tạo lúc', + source: 'Nguồn', + sharedTo: 'Chia sẻ với', + enabled: 'Đã bật', + vectorStore: 'Bộ lưu trữ vector', + fileStorage: 'Bộ lưu trữ tệp', + documentCount: 'Tài liệu', + faqCount: 'FAQ', + supportedFileTypes: 'Định dạng hỗ trợ', + chunking: 'Chunk', + parentShort: 'cha', + childShort: 'con' + }, + name: 'Tên', + description: 'Mô tả', + settings: 'Cài đặt', + sort: { + title: 'Sắp xếp', + updatedTime: 'Thời gian cập nhật', + updatedTimeDescription: 'Sắp xếp theo thay đổi gần nhất của từng tệp.', + createdTime: 'Thời gian tải lên/tạo', + createdTimeDescription: 'Mặc định. Xem tệp mới thêm hoặc tài liệu cũ nhất.', + fileName: 'Tên tệp', + fileNameDescription: 'Tìm nhanh tệp theo tên đã biết.', + recentlyUpdated: 'Cập nhật gần đây', + earliestUpdated: 'Cập nhật cũ nhất', + newestCreated: 'Mới tải lên nhất', + earliestCreated: 'Tải lên cũ nhất', + nameAscending: 'A–Z', + nameDescending: 'Z–A' + }, + tagUpdateSuccess: 'Đã cập nhật thẻ', + tagEditDialogHeading: 'Sửa thẻ', + folderTree: { + totalDocuments: 'Tổng cộng {count} tài liệu', + countHint: '{direct} tài liệu trong thư mục này; tổng cộng {total} gồm thư mục con', + filteredCount: '{count} tài liệu phù hợp', + title: 'Thư mục', + rootRow: 'Gốc', + rootRowTip: 'Gốc kho tri thức; chứa các tài liệu không nằm trong thư mục con', + folderCardCount: '{count} tài liệu', + searchingSubtree: '(bao gồm thư mục con)', + emptyFolder: 'Thư mục này chưa có tài liệu', + emptySearch: 'Không tìm thấy tài liệu phù hợp', + collapse: 'Thu gọn thư mục', + expand: 'Mở rộng thư mục', + collapseFolder: 'Thu gọn thư mục này', + expandFolder: 'Mở rộng thư mục này', + rename: 'Đổi tên', + renamePlaceholder: 'Tên thư mục', + renameSuccess: 'Đã đổi tên thư mục', + renameFailed: 'Không thể đổi tên thư mục', + renameInvalid: 'Không thể di chuyển thư mục vào chính nó' + }, + moveToFolder: { + action: 'Di chuyển vào thư mục', + newFolder: 'Thư mục con mới', + newFolderPlaceholder: 'Tên thư mục mới', + newFolderCreate: 'Tạo', + newFolderAddRoot: 'Thư mục con mới ở thư mục gốc', + newFolderAddUnder: 'Thư mục con mới trong “{folder}”', + newFolderHint: 'Nhấn Enter để tạo và di chuyển', + newFolderHintRoot: 'Sẽ được tạo tại thư mục gốc', + newFolderHintUnder: 'Sẽ được tạo trong “{folder}”', + success: 'Đã di chuyển {count} tài liệu', + failed: 'Không thể di chuyển tài liệu', + duplicate: 'Thư mục này đã tồn tại' + }, + tagFilterTitle: 'Lọc theo thẻ', + tagFilterPlaceholder: 'Thẻ', + tagFilterMulti: '{count} thẻ', + tagManageTitle: 'Quản lý thẻ', + tagManageDescription: 'Tạo, đổi tên hoặc xóa thẻ kho tri thức', + tagManageLink: 'Quản lý thẻ…', + tagManageListSection: 'Thẻ', + tagManageDocCount: '{count} tài liệu', + tagManageFaqCount: '{count} mục FAQ', + tagPickerSelected: 'Đã chọn', + tagPickerUnselected: 'Chưa chọn', + tagSelectedCount: 'Đã chọn {count}', + tagPickerSearch: 'Tìm hoặc tạo thẻ', + tagPickerInUse: 'Thẻ đang được sử dụng. Hãy gỡ liên kết khỏi tài liệu trước khi xóa.', + tagPickerDeleteConfirm: 'Xóa thẻ “{name}”?', + untagged: 'Chưa gắn thẻ', + tagCreateAction: 'Tạo thẻ', + tagSearchPlaceholder: 'Nhập để lọc thẻ', + tagNamePlaceholder: 'Nhập tên thẻ', + tagNameRequired: 'Vui lòng nhập tên thẻ', + tagCreateSuccess: 'Đã tạo thẻ', + tagEditSuccess: 'Đã cập nhật thẻ', + tagDeleteDescDoc: 'Xóa thẻ "{name}"? Tất cả tài liệu thuộc thẻ này cũng sẽ bị xóa.', + tagDeleteSuccess: 'Đã xóa thẻ', + tagEditAction: 'Đổi tên', + tagDeleteAction: 'Xóa', + tagEmptyResult: 'Không tìm thấy thẻ phù hợp', + tagLabel: 'Thẻ', + tagPlaceholder: 'Chọn thẻ', + noTags: 'Không có thẻ', + videosFilteredNoVLM: 'Đã bỏ qua {count} tệp video (chưa hỗ trợ tải lên video)', + unsupportedTypesHint: 'Một số định dạng tài liệu ({types}) chưa có trình phân tích phù hợp và không thể xử lý', + goToParserSettings: 'Cấu hình', + importURL: 'Nhập từ URL', + addDocument: 'Thêm tài liệu', + importURLTitle: 'Nhập từ URL', + urlRequired: 'Vui lòng nhập URL', + invalidURL: 'Vui lòng nhập URL hợp lệ', + urlImportSuccess: 'Nhập URL thành công!', + urlImportFailed: 'Nhập URL thất bại!', + urlExists: 'URL này đã tồn tại', + rebuildConfirm: 'Tạo lại tài liệu "{fileName}"? Hành động này sẽ xóa các Chunk hiện có và phân tích lại.', + rebuildSubmitted: 'Đã gửi yêu cầu tạo lại', + rebuildFailed: 'Tạo lại thất bại. Vui lòng thử lại sau', + rebuildInProgress: 'Tài liệu này đang được phân tích. Vui lòng thử lại sau', + cancelParse: 'Dừng phân tích', + cancelParseConfirmBody: 'Dừng phân tích "{title}"? Các Chunk đã ghi sẽ được giữ lại và có thể phân tích lại qua "Tạo lại"; các tác vụ tối ưu hóa đang chờ (tóm tắt / hỏi đáp / đồ thị tri thức) sẽ bị hủy ngay lập tức.', + cancelParseSubmitted: 'Đã dừng phân tích', + cancelParseFailed: 'Dừng thất bại, vui lòng thử lại sau', + draft: 'Bản nháp', + draftTip: 'Đã lưu tạm và không đưa vào truy xuất', + untitledDocument: 'Tài liệu không tên', + deleteDocument: 'Xóa tài liệu', + moveDocument: 'Di chuyển tới...', + moveToKnowledgeBase: 'Chuyển sang Kho tri thức', + moveNoTargets: 'Không tìm thấy kho tri thức tương thích (yêu cầu cùng loại và mô hình embedding)', + moveModeReuseVectors: 'Tái sử dụng vector (Nhanh)', + moveModeReuseVectorsDesc: 'Chuyển trực tiếp các Chunk và chỉ mục vector. Dùng khi cấu hình Chunk giống nhau.', + moveModeReparse: 'Phân tích lại', + moveModeReparseDesc: 'Phân tích lại tài liệu bằng cấu hình Chunk của kho tri thức đích.', + moveConfirm: 'Xác nhận chuyển', + moveConfirmTitle: 'Xác nhận cài đặt chuyển', + moveStarted: 'Đã gửi tác vụ chuyển', + moveFailed: 'Chuyển thất bại', + moveCompleted: 'Đã chuyển thành công', + moveCompletedWithErrors: 'Chuyển hoàn tất: {success} thành công, {failed} thất bại', + parsingFailed: 'Phân tích thất bại', + parsingInProgress: 'Đang phân tích...', + generatingSummary: 'Đang tạo tóm tắt...', + documentSummary: 'Tóm tắt', + detailSectionMeta: 'Thông tin cơ bản', + confirmDeleteDocument: 'Xác nhận xóa tài liệu "{fileName}"? Không thể khôi phục sau khi xóa', + confirmDelete: 'Xác nhận xóa', + viewModeGrid: 'Dạng lưới', + viewModeList: 'Dạng danh sách', + viewModeToggle: 'Chuyển chế độ xem', + columnName: 'Tên', + columnTag: 'Thẻ', + columnSize: 'Kích thước', + columnSource: 'Nguồn', + columnStatus: 'Trạng thái', + columnUpdatedAt: 'Đã cập nhật', + columnActions: 'Thao tác', + selectAll: 'Chọn tất cả', + selectedCount: 'Đã chọn {count}', + clearSelection: 'Bỏ chọn tất cả', + batchDelete: 'Xóa mục đã chọn', + batchDownload: 'Tải xuống mục đã chọn', + batchDownloading: 'Đang chuẩn bị tải xuống…', + batchDownloadHint: 'Tải tệp ZIP tối đa 200 tài liệu và 512 MiB nội dung gốc mỗi đợt. Chọn tất cả chỉ bao gồm tài liệu đã tải; các trang web không có tệp gốc sẽ bị bỏ qua. Tệp ZIP giữ nguyên cấu trúc thư mục của kho tri thức.', + batchDownloadStarted: 'Đang lưu tệp ZIP. Hãy giải nén rồi tải tệp và thư mục lên.', + batchDownloadFailed: 'Tải hàng loạt thất bại. Vui lòng thử lại.', + batchDownloadSkipped: 'Đã bỏ qua {count} tài liệu không có tệp gốc.', + batchDownloadNoFiles: 'Không có tài liệu nào được chọn chứa tệp gốc để tải.', + batchDownloadTooLarge: 'Tổng dung lượng tệp đã chọn vượt quá 512 MiB. Vui lòng giảm số lượng tài liệu và thử lại.', + selectLoaded: 'Chọn mục đã tải', + confirmBatchDeleteDocument: 'Xóa {count} tài liệu đã chọn? Không thể hoàn tác hành động này.', + deleteSubmitted: 'Đã gửi yêu cầu xóa. Đang chờ xử lý.', + deletePending: 'Đang chờ xóa. Hãy làm mới sau để kiểm tra kết quả.', + deleteTaskFailed: 'Xóa thất bại. Vui lòng kiểm tra chi tiết lỗi tài liệu và thử lại.', + deleteStatusUnavailable: 'Không thể xác nhận kết quả xóa. Hãy làm mới sau để kiểm tra trạng thái.', + batchDeleteSuccess: 'Đã xóa {count} tài liệu', + batchDeleteFailed: 'Xóa hàng loạt thất bại', + batchTag: 'Gắn thẻ hàng loạt', + batchTagDialogHeading: 'Gắn thẻ hàng loạt', + batchTagSubtitle: 'Thiết lập thẻ cho {count} tài liệu đã chọn (sẽ thay thế các thẻ hiện có)', + batchTagSuccess: 'Đã gắn thẻ cho {count} tài liệu', + batchTagFailed: 'Gắn thẻ hàng loạt thất bại', + confirmBatchReparseDocument: 'Tạo lại {count} tài liệu đã chọn? Nội dung hiện tại sẽ bị xóa và từng tài liệu sẽ được phân tích lại.', + confirmBatchReparse: 'Xác nhận và phân tích lại', + batchReparseSuccess: 'Đã gửi {count} tác vụ tạo lại', + batchReparseFailed: 'Tạo lại hàng loạt thất bại', + batchReparseSkippedInFlight: 'Đã bỏ qua {count} tài liệu đang trong quá trình phân tích', + statusCompleted: 'Hoàn tất', + statusProcessing: 'Đang xử lý', + statusFinalizing: 'Đang tối ưu', + statusStalled: 'Có thể bị treo', + stalledHint: 'Không có tiến triển trong {minutes} phút; tác vụ có thể đã bị treo. Mở nhật ký dấu vết để kiểm tra điểm dừng, hoặc dừng phân tích và tạo lại tài liệu.', + statusQueued: 'Trong hàng đợi', + queuedHint: 'Không có tiến triển trong {minutes} phút, nhưng các tác vụ vẫn đang chờ trong hàng đợi do quá tải. Hệ thống sẽ tự động tiếp tục xử lý.', + statusFailed: 'Thất bại', + statusCancelled: 'Đã hủy', + statusDraft: 'Bản nháp', + noDescription: 'Không có mô tả', + emptyKnowledgeDragDrop: 'Kho tri thức đang trống, kéo thả để tải lên', + pdfDocFormat: 'Định dạng PDF, DOC, tối đa 10MB', + textMarkdownFormat: 'Định dạng TXT, Markdown, tối đa 200KB', + dragFileNotText: 'Vui lòng kéo thả tệp thay vì văn bản hoặc liên kết', + searchPlaceholder: 'Tìm kiếm kho tri thức...', + docSearchPlaceholder: 'Tìm tên tài liệu...', + fileTypeFilter: 'Loại tệp', + allFileTypes: 'Tất cả định dạng', + allTags: 'Tất cả thẻ', + parseStatusFilter: 'Trạng thái', + allParseStatuses: 'Tất cả trạng thái', + parseStatusPending: 'Chờ xử lý', + parseStatusProcessing: 'Đang xử lý', + parseStatusCompleted: 'Hoàn tất', + parseStatusFinalizing: 'Đang tối ưu', + parseStatusFailed: 'Thất bại', + parseStatusCancelled: 'Đã hủy', + urlLabel: 'Địa chỉ URL', + urlPlaceholder: 'Nhập URL trang web, ví dụ: https://example.com', + urlTip: 'Hỗ trợ nhập nội dung từ trang web. Hệ thống sẽ tự động trích xuất và phân tích nội dung văn bản', + typeURL: 'URL', + typeManual: 'Thủ công', + typeFile: 'Tệp tin', + channelLabel: 'Kênh nguồn', + channelWeb: 'Web', + channelApi: 'API', + channelBrowserExtension: 'Tiện ích mở rộng trình duyệt', + channelWechat: 'WeChat', + channelWecom: 'WeCom', + channelFeishu: 'Feishu', + channelFeishuDrive: 'Feishu Drive', + channelLarkDrive: 'Lark Drive', + channelDingtalk: 'DingTalk', + channelSlack: 'Slack', + channelIm: 'Kênh tin nhắn (IM)', + channelNotion: 'Notion', + channelConfluence: 'Confluence', + channelYuque: 'Yuque', + channelGitLab: 'GitLab', + channelIma: 'Tencent IMA', + channelUpload: 'Tải lên', + channelManual: 'Thủ công', + channelUrl: 'Web', + channelUnknown: 'Không xác định', + urlSource: 'URL nguồn', + webContent: 'Nội dung Web', + documentContent: 'Nội dung tài liệu', + importTime: 'Thời gian nhập', + createTime: 'Thời gian tạo', + createdAt: 'Đã tạo', + updatedAt: 'Đã cập nhật', + clickToViewFull: 'Nhấp vào thẻ để xem toàn văn và các Chunk', + characters: 'ký tự', + segment: 'Chunk', + chunkCount: 'Tổng cộng {count} Chunk', + viewChunks: 'Xem Chunk', + viewMerged: 'Toàn văn', + generatedQuestions: 'Câu hỏi truy xuất', + viewParentContext: 'Xem ngữ cảnh cha', + parentContextLoadFailed: 'Không thể tải ngữ cảnh cha', + confirmDeleteQuestion: 'Bạn có chắc chắn muốn xóa câu hỏi này? Chỉ mục vector tương ứng cũng sẽ bị xóa.', + legacyQuestionCannotDelete: 'Không thể xóa câu hỏi định dạng cũ. Vui lòng tạo lại câu hỏi.', + customMetadata: 'Metadata tùy chỉnh', + metadataCapabilityHint: 'Dùng cho tóm tắt tài liệu và làm ngữ cảnh cấp tài liệu sau khi truy xuất; không lập chỉ mục và không ảnh hưởng đến xếp hạng truy xuất', + noCustomMetadata: 'Không có metadata tùy chỉnh', + addMetadataField: 'Thêm trường metadata', + metadataKeyPlaceholder: 'Tên trường', + metadataValuePlaceholder: 'Giá trị trường', + metadataTypeText: 'Văn bản', + metadataTypeNumber: 'Số', + metadataTypeBoolean: 'Boolean', + metadataTypeNull: 'Null', + metadataKeyRequired: 'Tên trường metadata là bắt buộc', + metadataKeyDuplicate: 'Trùng lặp trường metadata: {key}', + metadataNumberRequired: 'Trường metadata {key} phải là một số hợp lệ', + regenerateSummary: 'Tạo lại tóm tắt', + generateSummary: 'Tạo tóm tắt', + noDocumentSummary: 'Chưa có tóm tắt tài liệu', + summaryRefreshed: 'Đã làm mới tóm tắt', + summaryRefreshQueued: 'Đã đưa việc làm mới tóm tắt vào hàng đợi; sẽ tự động cập nhật khi sẵn sàng', + indexFailed: 'Đồng bộ chỉ mục thất bại', + chunkSavedIndexFailed: 'Đã lưu nội dung nhưng đồng bộ chỉ mục thất bại. Vui lòng thử lại chỉ mục.', + chunkEditConflict: 'Chunk này đã được chỉnh sửa bởi người khác. Danh sách đã được làm mới; vui lòng thử lại.', + retryIndex: 'Thử lại chỉ mục', + indexRetrySuccess: 'Đã đồng bộ chỉ mục', + chunkHistory: 'Lịch sử chỉnh sửa Chunk', + currentVersion: 'Phiên bản hiện tại', + noChunkHistory: 'Không có lịch sử chỉnh sửa', + compareRevisionWithCurrent: 'Thay đổi nội dung từ v{revision} sang v{current} hiện tại', + diffAddedInCurrent: 'Đã thêm ở bản hiện tại', + diffRemovedFromCurrent: 'Đã xóa ở bản hiện tại', + noContentChanges: 'Không có thay đổi nội dung; phiên bản này chỉ đổi trạng thái', + revertRevision: 'Khôi phục phiên bản', + revertRevisionConfirm: 'Khôi phục về v{revision}? Một bản sửa đổi mới sẽ được tạo.', + chunkReverted: 'Đã khôi phục Chunk', + chunkContentRequired: 'Nội dung Chunk là bắt buộc', + disableChunk: 'Vô hiệu hóa', + enableChunk: 'Kích hoạt', + enabledStatus: 'Đã bật', + disabledStatus: 'Đã tắt', + editChunkContent: 'Sửa nội dung Chunk', + addGeneratedQuestion: 'Thêm câu hỏi truy xuất', + regenerateQuestions: 'Tạo lại câu hỏi', + questionsRegenerated: 'Đã làm mới câu hỏi truy xuất', + staleGeneratedQuestions: 'Được tạo từ phiên bản cũ hơn; hãy tạo lại nếu cần', + noGeneratedQuestions: 'Không có câu hỏi truy xuất', + notInitialized: 'Kho tri thức chưa được khởi tạo. Vui lòng cấu hình mô hình trong cài đặt trước khi tải tệp lên', + missingStorageEngine: 'Kho tri thức này chưa chọn bộ lưu trữ. Vui lòng cấu hình bộ lưu trữ trong cài đặt trước khi tải nội dung lên.', + missingStorageEngineUpload: 'Vui lòng cấu hình bộ lưu trữ trước khi tải nội dung lên', + goToStorageSettings: 'Đến Cài đặt', + getInfoFailed: 'Không thể lấy thông tin kho tri thức, không thể tải tệp lên', + missingId: 'Thiếu ID kho tri thức', + deleteFailed: 'Xóa thất bại. Vui lòng thử lại sau!', + uploadTime: 'Thời gian tải lên', + newSession: 'Cuộc trò chuyện mới', + editDocument: 'Chỉnh sửa tài liệu', + rebuildDocument: 'Xây dựng lại tài liệu', + parseStatusDraft: 'Bản nháp', + sourceFilter: 'Nguồn', + allSources: 'Tất cả nguồn', + sourceApi: 'API', + sourceBrowserExtension: 'Tiện ích mở rộng', + sourceUpload: 'Tải lên', + sourceUrl: 'Nhập từ URL', + sourceManual: 'Thủ công', + updatedTimeFrom: 'Từ', + updatedTimeTo: 'Đến', + noMatch: 'Không tìm thấy kho tri thức phù hợp', + noKnowledge: 'Chưa có kho tri thức nào', + loadingFailed: 'Không thể tải kho tri thức', + operationNotSupportedForType: 'Thao tác không được hỗ trợ cho loại kho tri thức này', + allFilesSkippedNoEngine: 'Đã bỏ qua tất cả tệp do không có công cụ phân tích', + filesSkippedNoEngine: 'Đã bỏ qua {count} tệp do không có công cụ phân tích', + deleteSuccess: 'Xóa tri thức thành công!', + chunkLoadFailed: 'Không thể tải Chunk' + }, + agent: { + manageAgents: 'Quản lý', + builtinAgents: 'Agent mặc định', + customAgents: 'Agent tùy chỉnh', + capabilities: { + kbCount: 'Đã chọn {count} kho tri thức', + kbAll: 'Toàn quyền truy cập kho tri thức', + mcpEnabled: 'Đã bật dịch vụ MCP', + multiTurn: 'Hội thoại đa lượt' + }, + type: { + normal: 'Phản hồi nhanh', + agent: 'Suy luận thông minh' + }, + mode: { + normal: 'Phản hồi nhanh', + agent: 'Suy luận thông minh' + }, + features: { + webSearch: 'Tìm kiếm web đã bật', + knowledgeBase: 'Đã liên kết kho tri thức', + mcp: 'Dịch vụ MCP đã bật', + multiTurn: 'Hội thoại đa lượt' + }, + tabs: { + sharedToMe: 'Được chia sẻ với tôi' + }, + sections: { + builtin: 'Mặc định', + mine: 'Tôi đã tạo', + tenantOthers: 'Không gian làm việc · Thành viên khác', + tenantReadonly: 'Không gian làm việc · Chỉ xem', + sharedByMe: 'Tôi đã chia sẻ', + sharedEditable: 'Được chia sẻ · Có thể chỉnh sửa', + sharedReadonly: 'Được chia sẻ · Chỉ xem' + }, + empty: { + title: 'Chưa có Agent tùy chỉnh', + description: 'Nhấp vào nút ở góc trên bên phải để tạo agent đầu tiên', + sharedTitle: 'Chưa có agent nào được chia sẻ', + sharedDescription: 'Bạn có thể tham gia không gian hoặc yêu cầu người khác chia sẻ agent với bạn', + favoritesTitle: 'Chưa có mục yêu thích', + favoritesDescription: 'Gắn sao trên thẻ agent để thêm vào đây', + recentsTitle: 'Chưa có hoạt động gần đây', + recentsDescription: 'Các agent bạn đã sử dụng gần đây sẽ xuất hiện ở đây' + }, + detail: { + title: 'Chi tiết Agent', + useInChat: 'Dùng trong Chat' + }, + shareScope: { + title: 'Phạm vi chia sẻ', + desc: 'Thành viên trong không gian có quyền chỉ xem agent này và sẽ sử dụng theo cấu hình hiện tại của bạn; các thay đổi đối với agent sẽ tự động đồng bộ tới các không gian được chia sẻ. Để cho phép thành viên chỉnh sửa nội dung kho tri thức, hãy chia sẻ riêng kho tri thức đó vào không gian.', + skillSecretsWarning: 'Agent này sử dụng kỹ năng. Khi các thành viên trong không gian sử dụng, các kỹ năng sẽ chạy trong Sandbox của không gian làm việc này với các biến môi trường do quản trị viên thiết lập (chẳng hạn như khóa API), và thành viên có thể yêu cầu agent hiển thị các giá trị này. Chỉ chia sẻ nếu bạn chấp nhận điều này.', + knowledgeBase: 'Kho tri thức', + chatModel: 'Mô hình trò chuyện', + rerankModel: 'Mô hình Rerank', + webSearch: 'Tìm kiếm web', + mcp: 'Dịch vụ MCP', + kbAll: 'Tất cả kho tri thức', + kbSelected: 'Đã chọn {count}', + kbNone: 'Không có', + modelConfigured: 'Đã cấu hình', + modelNotSet: 'Chưa thiết lập', + enabled: 'Bật', + disabled: 'Tắt', + mcpAll: 'Tất cả dịch vụ', + mcpSelected: 'Đã chọn {count}', + mcpNone: 'Không có' + }, + delete: { + confirmTitle: 'Xóa Agent', + confirmMessage: 'Bạn có chắc chắn muốn xóa agent "{name}"? Thao tác này không thể hoàn tác.', + confirmButton: 'Xác nhận xóa' + }, + messages: { + created: 'Tạo agent thành công', + updated: 'Cập nhật agent thành công', + deleted: 'Đã xóa agent', + deleteFailed: 'Xóa thất bại', + saveFailed: 'Lưu thất bại', + copied: 'Sao chép agent thành công', + copyFailed: 'Sao chép thất bại', + disabled: 'Đã tắt agent', + enabled: 'Đã bật agent' + }, + editor: { + reasoningEffortUnsupported: 'Mô hình đã chọn không hỗ trợ suy luận; mọi tùy chọn ngoài "Tắt" đều bị bỏ qua.', + reasoningEffortAlwaysOn: 'Mô hình đã chọn luôn suy luận và không thể tắt; bạn chỉ có thể thay đổi mức độ suy luận.', + createTitle: 'Tạo Agent', + editTitle: 'Chỉnh sửa Agent', + buttons: { + create: 'Tạo Agent', + saveAndClose: 'Lưu và đóng' + }, + postCreateHint: { + title: 'Tạo thành công', + footer: 'Tiếp tục điều chỉnh cài đặt, cấu hình chia sẻ và xuất bản, sau đó nhấp "Lưu và đóng".', + integrationDesc: 'Vào mục Tích hợp để cấu hình ứng dụng nhắn tin, nhúng web và các kênh phát hành khác' + }, + basicInfo: 'Thông tin cơ bản', + basicInfoDesc: 'Cấu hình tên, mô tả và chế độ chạy của agent', + promptsConfig: 'Prompt (Prompt)', + promptsConfigDesc: 'Cấu hình prompt hệ thống, ngữ cảnh, ý định, viết lại và dự phòng', + modelConfig: 'Cấu hình mô hình', + modelConfigDesc: 'Cấu hình mô hình trò chuyện, mô hình phụ trợ (Rerank) và tham số sinh văn bản', + toolsConfig: 'Công cụ', + toolsConfigDesc: 'Cấu hình các công cụ khả dụng cho Agent', + knowledgeConfig: 'Kho tri thức', + knowledgeConfigDesc: 'Cấu hình phạm vi kho tri thức và chiến lược FAQ cho agent', + webSearchConfig: 'Tìm kiếm web', + webSearchConfigDesc: 'Cấu hình khả năng tìm kiếm web cho agent', + agentId: 'ID Agent', + agentIdDesc: 'Dùng ID này để định danh agent khi tích hợp API', + name: 'Tên', + namePlaceholder: 'Nhập tên agent', + nameRequired: 'Tên agent là bắt buộc', + systemPromptRequired: 'Prompt hệ thống là bắt buộc', + modelRequired: 'Vui lòng chọn một mô hình', + queryMissingInRewrite: 'Prompt viết lại của người dùng phải chứa biến {\'{{\'}query{\'}}\'}', + queryMissingInFallback: 'Prompt dự phòng phải chứa biến {\'{{\'}query{\'}}\'}', + description: 'Mô tả', + descriptionPlaceholder: 'Nhập mô tả agent', + normalDesc: 'Phản hồi nhanh, trả lời trực diện', + agentDesc: 'Suy luận nhiều bước, phân tích sâu cho các câu hỏi phức tạp', + model: 'Mô hình', + modelPlaceholder: 'Chọn mô hình', + systemPrompt: 'Prompt hệ thống', + systemPromptPlaceholder: 'Prompt hệ thống tùy chỉnh để xác định vai trò và hành vi của Agent (dùng biến {\'{{\'}web_search_status{\'}}\'} để lấy trạng thái tìm kiếm web động)', + contextTemplateRequired: 'Mẫu ngữ cảnh là bắt buộc', + temperature: 'Temperature', + thinking: 'Chế độ suy luận', + citationEnabled: 'Hiện nguồn trích dẫn', + citationEnabledDesc: 'Hiển thị nguồn từ kho tri thức và web trong câu trả lời; khi tắt, quá trình truy xuất vẫn hoạt động', + mode: 'Chế độ chạy', + webSearch: 'Tìm kiếm web', + webSearchProvider: 'Công cụ tìm kiếm', + webSearchProviderPlaceholder: 'Dùng công cụ tìm kiếm mặc định', + webSearchMaxResults: 'Số kết quả tìm kiếm tối đa', + webFetchEnabled: 'Tự động trích xuất nội dung trang', + webFetchTopN: 'Số trang cần trích xuất', + knowledgeBases: 'Kho tri thức', + allKnowledgeBases: 'Tất cả kho tri thức', + selectedKnowledgeBases: 'Kho tri thức đã chọn', + noKnowledgeBase: 'Không có kho tri thức', + selectKnowledgeBases: 'Chọn kho tri thức', + selectKnowledgeBasesDesc: 'Chọn các kho tri thức cần liên kết (bao gồm kho cộng tác)', + myKnowledgeBases: 'Kho tri thức của tôi', + sharedKnowledgeBases: 'Kho tri thức cộng tác', + retrieveKBOnlyWhenMentioned: 'Chỉ truy xuất khi được nhắc tới', + retrieveKBOnlyWhenMentionedDesc: 'Tắt: tự động truy xuất kho tri thức đã cấu hình; Bật: chỉ truy xuất khi người dùng nhắc tới bằng {\'@\'}', + rerankModel: 'Mô hình Rerank', + rerankModelDesc: 'Dùng để Rerank kết quả truy xuất kho tri thức nhằm tăng độ chính xác', + rerankModelPlaceholder: 'Chọn mô hình Rerank', + rerankModelOptionalHint: 'Không có kho tri thức RAG nào trong phạm vi hiện tại, vì vậy mục này là tùy chọn. Nếu thêm kho tri thức sau đó, mô hình Rerank mặc định của không gian làm việc sẽ được dùng thay thế. Khuyến nghị vẫn nên cấu hình cụ thể.', + maxIterations: 'Số vòng lặp tối đa', + maxIterationsLimit: 'Giới hạn', + maxIterationsUnlimited: 'Không giới hạn', + allowedTools: 'Công cụ được phép dùng', + multiTurn: 'Hội thoại đa lượt', + historyTurns: 'Số lượt hội thoại lưu nhớ', + retainRetrievalHistory: 'Lưu kết quả truy xuất', + memoryEnabled: 'Bộ nhớ dài hạn', + retrievalStrategy: 'Chiến lược truy xuất', + embeddingTopK: 'Top K Embedding', + keywordThreshold: 'Ngưỡng từ khóa', + vectorThreshold: 'Ngưỡng vector', + rerankTopK: 'Top K Rerank', + rerankThreshold: 'Ngưỡng Rerank', + conversationSettings: 'Hội thoại', + contextTemplate: 'Mẫu ngữ cảnh', + contextTemplatePlaceholder: 'Mẫu ngữ cảnh tùy chỉnh...', + enableQueryExpansion: 'Mở rộng truy vấn', + enableRewrite: 'Viết lại truy vấn', + queryUnderstandModel: 'Mô hình hiểu truy vấn', + queryUnderstandModelPlaceholder: 'Để trống để dùng lại mô hình chat chính', + rewritePromptSystem: 'Prompt hệ thống viết lại', + rewritePromptSystemPlaceholder: 'Để trống để dùng Prompt mặc định', + rewritePromptUser: 'Prompt người dùng viết lại', + rewritePromptUserPlaceholder: 'Để trống để dùng Prompt mặc định', + maxCompletionTokens: 'Số token phản hồi tối đa', + maxCompletionTokensDefault: 'Mặc định', + maxCompletionTokensCustom: 'Tùy chỉnh', + fallbackStrategy: 'Chiến lược dự phòng', + fallbackResponse: 'Câu phản hồi cố định', + fallbackResponsePlaceholder: 'Xin lỗi, tôi không thể trả lời câu hỏi này.', + fallbackPrompt: 'Prompt dự phòng', + fallbackPromptPlaceholder: 'Để trống để dùng Prompt mặc định', + skillsConfig: 'Kỹ năng', + skillsConfigDesc: 'Chọn một Sandbox đang chạy, sau đó chọn kỹ năng bên dưới. Kỹ năng chưa có trên Sandbox sẽ hiện nút Cài đặt và chỉ kích hoạt được sau khi cài đặt.', + skillsSelection: 'Danh sách kỹ năng', + skillsSelectionDesc: 'Toàn bộ kỹ năng của không gian làm việc hiển thị ở đây. Kỹ năng đã cài đặt có thể dùng ngay; các kỹ năng khác cần được cài đặt trước.', + skillsAll: 'Tất cả', + skillsSelected: 'Đã chọn', + skillsNone: 'Đã tắt', + selectSkills: 'Chọn kỹ năng', + selectSkillsDesc: 'Chọn các kỹ năng Agent này sẽ dùng. Kỹ năng chưa cài đặt không thể kích hoạt — hãy nhấn Cài đặt ở bên phải trước.', + skillsAllListHint: 'Mục \'Tất cả\' chỉ bao gồm các kỹ năng đã cài đặt trên Sandbox này. Kỹ năng chưa cài đặt sẽ không được thêm cho đến khi bạn cài đặt chúng.', + skillsGroupAvailable: 'Khả dụng', + skillsGroupUnavailable: 'Không khả dụng', + noSkillsAvailable: 'Danh mục của không gian làm việc chưa có kỹ năng nào.', + skillsNeedSandbox: 'Vui lòng chọn Sandbox trước.', + goSandboxSettings: 'Quản lý Sandbox', + goSkillSettings: 'Quản lý kỹ năng', + installToThisSandbox: 'Cài đặt vào Sandbox này', + upgradeOnThisSandbox: 'Nâng cấp Sandbox này lên phiên bản danh mục', + installShort: 'Cài đặt', + viewInstallProgress: 'Xem tiến trình', + skillNotInstalled: 'Chưa cài đặt', + skillNotReady: 'Chưa sẵn sàng', + skillDisabledOnSandbox: 'Đã tắt trên Sandbox này', + sandboxBackend: 'Sandbox', + sandboxBackendDefault: 'Đã tắt', + sandboxBackendHint: 'Kịch bản kỹ năng sẽ không chạy cho đến khi chọn một Sandbox.', + sandboxBackendMissing: 'Cấu hình đã bị xóa', + sandboxNoConfigs: 'Không gian làm việc này chưa có Sandbox, kịch bản kỹ năng sẽ không thể chạy.', + skillsInfoTitle: 'Cách Kỹ năng và Sandbox phối hợp', + skillsInfoContent: 'Kỹ năng là các mô-đun tri thức có kịch bản chạy trong Sandbox đã chọn. Danh sách kỹ năng lấy từ các kỹ năng đã cài trên Sandbox đó. Khi một phiên Sandbox được tạo, tệp đính kèm, Artifacts và việc dọn dẹp sẽ gắn cố định với cấu hình khởi tạo — việc đổi Sandbox chỉ áp dụng cho các phiên sau.', + hostSkillsConfigDesc: 'Chọn các kỹ năng đã được cài đặt trên máy chủ này. Kỹ năng chưa cài đặt sẽ hiển thị nút Cài đặt và chỉ có thể chọn sau khi cài đặt xong.', + hostSkillsSelectionDesc: 'Danh sách kỹ năng trong không gian làm việc. Các kỹ năng đã cài đặt trên máy chủ này có thể sử dụng ngay; hãy cài đặt các kỹ năng còn lại trước.', + hostSelectSkillsDesc: 'Chọn các kỹ năng mà Agent này sẽ sử dụng. Kỹ năng chưa có trên máy chủ này không thể chọn — hãy nhấn Cài đặt trước.', + hostSkillsAllListHint: 'Mục Tất cả chỉ bao gồm các kỹ năng đã cài đặt trên máy chủ này. Các kỹ năng khác sẽ bị bỏ qua cho đến khi bạn cài đặt chúng.', + hostInstallToThisComputer: 'Cài đặt trên máy chủ này', + hostUpgradeOnThisComputer: 'Nâng cấp kỹ năng trên máy chủ này lên phiên bản danh mục', + hostSkillDisabled: 'Đã vô hiệu hóa trên máy chủ này' + }, + taskLabel: 'Tác vụ:', + think: 'Suy luận', + copy: 'Sao chép', + addToKnowledgeBase: 'Thêm vào Kho tri thức', + artifactDrawer: { + buttonTitle: 'Xem các tệp tạo từ phản hồi này', + title: 'Artifacts', + empty: 'Không có tệp tải xuống nào được tạo trong lượt này.', + preview: 'Xem trước', + previewBack: 'Quay lại danh sách', + collecting: 'Đang lưu Artifacts…', + delete: 'Xoá', + deleteTitle: 'Xoá tệp này?', + deleteConfirm: '“{name}” và dữ liệu liên quan sẽ bị xoá vĩnh viễn. Không thể hoàn tác thao tác này.', + deleted: 'Đã xoá tệp', + deleteFailed: 'Xoá thất bại, vui lòng thử lại.', + download: 'Tải xuống', + downloadFailed: 'Tải xuống thất bại, vui lòng thử lại.', + inlinePreviewHint: 'Nhấp để xem trước', + inlineMissing: 'Tệp không khả dụng', + inlineDeleted: 'Tệp đã bị xoá' + }, + updatePlan: 'Cập nhật kế hoạch', + webSearchFound: 'Tìm thấy {count} kết quả web', + toolFallback: 'Công cụ', + stepsCompleted: 'Đã hoàn thành {steps} bước', + reasoningRounds: '{rounds} vòng suy luận', + toolCalls: '{tools} lượt gọi công cụ', + durationSuffix: '{duration}', + stepSummarySeparator: ' · ', + contextCompacted: 'Đã nén ngữ cảnh', + contextCompactedSummary: '{before} → {after} token', + contextCompactedDegraded: 'Không thể tạo tóm tắt, giữ nguyên bản ghi gốc', + title: 'Agent', + subtitle: 'Cấu hình và quản lý các agent để tùy chỉnh hành vi và năng lực hội thoại', + createAgent: 'Tạo Agent', + builtin: 'Mặc định', + disabled: 'Đã tắt', + disable: 'Tắt', + enable: 'Bật', + noDescription: 'Không có mô tả', + selectAgent: 'Chọn Agent', + noAgents: 'Không có agent nào', + selector: { + title: 'Chọn Agent', + current: 'Hiện tại', + goToSettings: 'Cài đặt', + sharedLabel: 'Được chia sẻ', + notReadyHint: 'Chưa sẵn sàng. Cần cấu hình: {items}', + notReadyStatus: 'Cần thiết lập', + configureAction: 'Cấu hình', + sharedNotReadyContact: 'Liên hệ quản trị viên tổ chức chia sẻ để hoàn tất thiết lập', + capabilitiesSection: 'Khả năng', + webSearchCapability: 'Tìm kiếm web', + imageUploadCapability: 'Tải lên hình ảnh', + capabilityEnabled: 'Bật', + capabilityDisabled: 'Tắt', + capabilitySupported: 'Hỗ trợ', + capabilityUnsupported: 'Không hỗ trợ', + capabilityUnconfigured: 'Chưa thiết lập' + } + }, + uploadConfirm: { + documentSummary: 'Tóm tắt tài liệu', + documentSummaryDescription: 'Tự động tóm tắt các tài liệu trong lần nhập này.', + generateSummary: 'Tạo tóm tắt tài liệu', + generateSummaryHint: 'Bật theo mặc định. Tắt để bỏ qua tóm tắt trong khi vẫn tiếp tục phân tích, đánh chỉ mục và các bước khác.', + title: 'Xác nhận tải lên', + parseConfig: 'Cấu hình phân tích', + configNav: 'Điều hướng cấu hình phân tích', + navParserDefault: 'Mặc định', + navParserCustomized: 'Tùy chỉnh', + moreOptions: 'Tùy chọn xử lý khác', + summaryParentChildShort: 'Cha - con', + summaryParserForceScanned: 'Chế độ quét', + summaryQuestionCountValue: '{count}', + summaryGraphTagsValue: '{count}', + navChunkingSummary: 'Đoạn {size}', + statusOn: 'Bật', + statusOff: 'Tắt', + notSet: 'Chưa đặt', + summaryNoTags: 'Chưa đặt', + summaryTagsCount: '{count} thẻ', + confirm: 'Tải lên và phân tích', + cancel: 'Hủy', + tabTags: 'Thẻ tài liệu', + tagsDescription: 'Chọn một hoặc nhiều thẻ cho mọi tài liệu trong đợt nhập này', + tagsPlaceholder: 'Chọn thẻ (cho phép chọn nhiều)', + tagsEmpty: 'Kho tri thức này chưa có thẻ. Bạn có thể tạo trong mục quản lý thẻ sau khi tải lên.', + tagsLoadFailed: 'Không thể tải thẻ. Bạn có thể gắn thẻ sau từ danh sách tài liệu.', + noItems: 'Thêm ít nhất một tệp hoặc URL', + urlItemLabel: 'URL', + urlAdded: 'Đã thêm URL', + urlDuplicate: 'URL này đã có trong danh sách', + statusNeedsSetup: 'Cần thiết lập', + multimodalSetupHint: 'Đã phát hiện hình ảnh. Bật đa phương thức và chọn một mô hình.', + asrSetupHint: 'Đã phát hiện âm thanh. Bật nhận dạng giọng nói và chọn một mô hình.', + vlmModelRequired: 'Cấu hình mô hình đa phương thức', + asrModelRequired: 'Cấu hình mô hình nhận dạng giọng nói', + vlmModelSelectRequired: 'Đã bật đa phương thức. Vui lòng chọn mô hình VLM.', + asrModelSelectRequired: 'Đã bật nhận dạng giọng nói. Vui lòng chọn mô hình ASR.', + pdfForceScanned: { + label: 'Buộc phân tích PDF dạng quét', + description: 'Phù hợp cho PDF in từ web, bản scan hoặc nhiều hình ảnh. Mỗi trang sẽ được kết xuất thành ảnh và xử lý qua OCR/VLM. Có thể tăng thời gian xử lý và chi phí mô hình.' + }, + continueAdd: 'Thêm tiếp', + destinationLabel: 'Vị trí tải lên', + destinationChange: 'Đổi vị trí tải lên', + destinationToRoot: 'Dùng thư mục gốc', + folderUploadTitle: 'Thư mục “{name}”', + folderUploadHint: '{count} tệp; giữ nguyên cấu trúc thư mục cục bộ', + filesAdded: 'Đã thêm {count} tệp', + filesAllDuplicate: 'Các tệp được chọn đã có trong danh sách', + titleManual: 'Xác nhận xuất bản trực tuyến', + confirmManual: 'Xuất bản và phân tích', + titleReparse: 'Xác nhận phân tích lại', + confirmReparse: 'Xác nhận và phân tích lại', + reparseSource: 'Tài liệu cần phân tích lại', + reparseHint: 'Dùng lại cấu hình phân tích trước; chỉnh sửa tại đây', + manualCharCount: '{count} ký tự' + }, + knowledgeStages: { + title: 'Quy trình xử lý', + root: 'Xử lý tri thức', + processConfig: { + title: 'Cấu hình phân tích cho lượt chạy này', + kbDefault: 'Dùng mặc định của kho tri thức', + graph: 'Đồ thị tri thức' + }, + attempt: 'Lần thử {n}', + retry: 'Thử phân tích lại', + notRun: 'Chưa chạy', + stageFailed: '{stage} thất bại', + copyError: 'Sao chép chi tiết lỗi', + stat: { + duration: 'Thời lượng', + attempt: 'Lần thử', + tasks: 'Tác vụ nền', + tasksValue: '{running} đang chạy · {failed} thất bại · {completed} xong' + }, + refresh: 'Làm mới ngay', + copy: 'Sao chép', + copyDetails: 'Sao chép chi tiết', + copied: 'Đã sao chép vào bộ nhớ tạm', + close: 'Đóng', + live: 'TRỰC TIẾP', + liveTooltip: 'Đang phân tích — tự động làm mới mỗi 2 giây', + autoRefreshOn: 'Đang tự động làm mới', + fetchFailedShort: 'tải thất bại', + viewTrace: 'Xem trace', + expandBranch: 'Mở rộng nhánh con', + collapseBranch: 'Thu gọn nhánh con', + rowSelectHint: 'Nhấp để xem chi tiết; dùng mũi tên để mở rộng hoặc thu gọn nhánh con', + resizeDrawer: 'Kéo để chỉnh độ rộng bảng', + justNow: 'vừa xong', + secondsAgo: '{n} giây trước', + minutesAgo: '{n} phút trước', + noActivity: 'Chưa có hoạt động phân tích nào', + totalDuration: 'Tổng: {d}', + stall: { + title: 'Không có tiến triển trong {minutes} phút; có thể bị treo', + hint: 'Bạn có thể tiếp tục chờ, hoặc dừng phân tích và xử lý lại tài liệu. Nếu vẫn không có tiến triển, tác vụ sẽ tự động đánh dấu thất bại.', + hintAtStage: 'Đã dừng tại giai đoạn {stage}. Bạn có thể tiếp tục chờ, hoặc dừng phân tích và xử lý lại tài liệu. Nếu vẫn không có tiến triển, tác vụ sẽ tự động đánh dấu thất bại.', + queuedTitle: 'Không có tiến triển trong {minutes} phút; vẫn đang chờ trong hàng đợi', + queuedHint: 'Các tác vụ của tài liệu này vẫn đang chờ, thường do nghẽn hàng đợi. Hệ thống sẽ tự động tiếp tục; thường không cần thao tác gì thêm.' + }, + head: { + lastProgress: 'Tiến độ gần nhất', + stagesDone: 'Giai đoạn chính', + stagesProgress: 'Giai đoạn hiện tại', + attempt: 'Lần thử', + updated: 'Đã cập nhật' + }, + tab: { + overview: 'Tổng quan', + raw: 'JSON gốc' + }, + detail: { + started: 'Bắt đầu', + finished: 'Kết thúc', + duration: 'Thời lượng', + offset: 'Độ lệch', + timing: 'Thời gian', + identity: 'Định danh', + stageBreakdown: 'Chi tiết giai đoạn', + stageOrder: 'Thứ tự giai đoạn', + childCount: 'Span con', + kind: 'Loại', + status: 'Trạng thái', + name: 'Tên', + input: 'Đầu vào', + output: 'Đầu ra', + metadata: 'Metadata', + traceMetadata: 'Metadata trace', + metadataHint: 'Các trường phụ trợ cho việc giám sát (vd: Langfuse trace ID). Dữ liệu giai đoạn/span con nằm ở mục Đầu vào và Đầu ra.', + metadataEmpty: 'Span này không có metadata. Xem dữ liệu tại Đầu vào/Đầu ra; các trường cấp trace sẽ hiển thị ở Tổng quan khi kết nối Langfuse.', + error: 'Lỗi', + empty: 'Không có dữ liệu', + inProgress: 'Đang xử lý', + elapsed: 'Đã trôi qua', + placeholderHint: 'Giai đoạn này không có bản ghi span chi tiết; chỉ hiển thị trạng thái suy luận.', + showJson: 'Mở rộng JSON', + hideJson: 'Thu gọn JSON', + includingChildren: 'gồm span con' + }, + stage: { + docreader: 'Phân tích tài liệu', + chunking: 'Chunk', + embedding: 'Embedding', + multimodal: 'Nhận diện đa phương thức', + postprocess: 'Hậu xử lý' + }, + status: { + pending: 'Chờ xử lý', + running: 'Đang chạy', + finalizing: 'Đang hoàn tất', + done: 'Hoàn thành', + failed: 'Thất bại', + skipped: 'Đã bỏ qua', + cancelled: 'Đã huỷ' + }, + errorCode: { + TASK_STALLED: 'Đã dừng do không có tiến triển', + TASK_STALLED_SUGGESTION: 'Quá trình xử lý vượt quá giới hạn thời gian và không còn tác vụ nào trong hàng đợi nên đã được đánh dấu thất bại. Nhấn Thử lại; nếu lỗi tiếp diễn, hãy kiểm tra dịch vụ liên quan (phân tích tài liệu, mô hình hoặc bộ lưu trữ vector).', + UNKNOWN_SUGGESTION: 'Kiểm tra nhật ký ứng dụng để biết thêm chi tiết.', + DOCREADER_UNAVAILABLE: 'Dịch vụ bóc tách tài liệu không khả dụng', + DOCREADER_UNAVAILABLE_SUGGESTION: 'Không thể kết nối đến DocReader hoặc kết nối đã bị ngắt. Hãy kiểm tra trạng thái dịch vụ, vòng lặp khởi động lại và kết nối mạng. Thử lại sau khi dịch vụ phục hồi; không cần tải lại tệp.', + DOCREADER_TIMEOUT: 'Hết thời gian bóc tách tài liệu', + DOCREADER_TIMEOUT_SUGGESTION: 'Kiểm tra trạng thái hoạt động và tải của DocReader trước khi thử lại. Hãy chia nhỏ tệp nếu cần.', + DOCREADER_PARSE_FAILED: 'Bóc tách tài liệu thất bại', + DOCREADER_PARSE_FAILED_SUGGESTION: 'Kiểm tra định dạng tệp và yêu cầu quản trị viên kiểm tra nhật ký DocReader cho lần xử lý này.' + } + }, + settings: { + modelManagement: 'Quản lý mô hình', + webSearchConfig: 'Tìm kiếm web', + autoCheckUpdate: 'Tự động tải bản cập nhật', + autoCheckUpdateDesc: 'Tự động kiểm tra và tải về phiên bản mới nhất ở chế độ nền.', + vectorStoreEngine: 'Động cơ Vector DB', + parserEngine: 'Động cơ phân tích tài liệu', + storageEngine: 'Động cơ lưu trữ', + sandbox: { + title: 'Cấu hình Sandbox', + description: 'Cấu hình môi trường thực thi cô lập cho kịch bản kỹ năng của agent. Mỗi agent sẽ chọn một cấu hình trong không gian làm việc.', + pageHintTitle: 'Sandbox là gì?', + pageHint: 'Sandbox là môi trường cô lập để chạy kịch bản kỹ năng của agent. Một không gian làm việc có thể có nhiều cấu hình (Docker, E2B, CubeSandbox); mỗi agent chọn một cấu hình tương ứng. Kỹ năng được cài đặt trong trang Quản lý kỹ năng vào image của cấu hình đã chọn. Kịch bản sẽ bị vô hiệu hóa cho đến khi chọn cấu hình.', + editorDescription: 'Cấu hình môi trường thực thi cho không gian làm việc. Docker, CubeSandbox và E2B dùng chung quy trình quản lý.', + stepConnection: 'Kết nối', + stepTemplate: 'Mẫu', + stepRuntime: 'Môi trường thực thi', + stepSkills: 'Kỹ năng', + stepSkillsLocked: 'Kỹ năng được cài trực tiếp vào image của cấu hình này. Hãy lưu cấu hình trước khi chuyển sang bước này.', + setupProgress: 'Tiến trình thiết lập Sandbox', + stepDescriptions: { + connection: 'Cấu hình backend và kiểm tra kết nối trước khi tải mẫu.', + template: 'Chọn mẫu sẵn sàng từ cụm máy chủ đã kết nối.', + runtime: 'Cấu hình thiết lập thực thi, biến môi trường, thời điểm cập nhật image kỹ năng, sau đó lưu lại.', + skills: 'Cài đặt kỹ năng vào image Sandbox của cấu hình này. Có thể quay lại bất kỳ lúc nào sau khi lưu.' + }, + back: 'Quay lại', + connectAndContinue: 'Kết nối và tiếp tục', + loading: 'Đang tải cấu hình Sandbox...', + loadFailed: 'Không thể tải cấu hình Sandbox', + backend: 'Sandbox', + backendType: 'Loại Sandbox', + backendTypePlaceholder: 'Chọn loại Sandbox', + scriptPolicyLabel: 'Cho phép chạy kịch bản kỹ năng trong Sandbox', + scriptPolicyDesc: 'Khi tắt, agent trong không gian làm việc này chỉ có thể đọc nội dung kỹ năng. Các Sandbox từ xa đang hoạt động sẽ được giải phóng khi kết thúc phiên.', + backendDescriptions: { + cube: 'Cụm MicroVM tự lưu trữ cho môi trường triển khai nội bộ hoặc on-premises', + e2b: 'Dịch vụ MicroVM được quản lý hoặc hệ thống tương thích E2B', + docker: 'Duy trì container dài hạn theo phiên trên máy chủ WeKnora này; kịch bản và tệp được lưu trong container đó' + }, + dockerDisabledAlert: 'Sandbox Docker chưa được bật trên bản triển khai này', + dockerDisabledHint: 'docker.sock cục bộ tương đương với quyền root trên máy chủ. Với cài đặt máy đơn riêng tư, quản trị viên có thể bật tại Cài đặt → Cài đặt hệ thống → An ninh mạng.', + dockerDisabledCard: 'Sandbox Docker đã bị tắt trên bản triển khai này; cấu hình này sẽ không tạo container', + dockerHostRisk: 'Để trống hoặc dùng unix:// sẽ sử dụng Docker daemon trên máy chủ WeKnora, tương đương quyền root trên máy chủ. Chỉ dùng cho bản cài đặt đơn nút riêng tư. Nên ưu tiên Cube hoặc E2B khi dùng chung máy chủ giữa nhiều không gian làm việc. Endpoint tcp:// từ xa bắt buộc có thư mục chứng chỉ TLS.', + addConfig: 'Thêm Sandbox', + viewClusterGuide: 'Hướng dẫn thiết lập cụm', + configName: 'Tên cấu hình', + configNamePlaceholder: 'Ví dụ: Production E2B', + configNameRequired: 'Vui lòng nhập tên cấu hình', + configDescription: 'Mô tả', + configDescriptionPlaceholder: 'Không bắt buộc, giúp phân biệt các cấu hình cùng loại', + createTitle: 'Thêm Sandbox', + editTitle: 'Chỉnh sửa Sandbox', + sectionBasic: 'Thông tin cơ bản', + sectionConnection: 'Kết nối cụm máy chủ', + sectionRuntimeEnvironment: 'Môi trường thực thi', + sectionTemplate: 'Mẫu môi trường thực thi', + sectionRuntime: 'Cài đặt thực thi', + sectionNetwork: 'Chính sách mạng', + sectionEnvironment: 'Biến môi trường', + networkHint: 'Kiểm soát kết nối chiều ra (egress) cho mọi Sandbox dùng cấu hình này. Thay đổi chỉ áp dụng cho Sandbox tạo mới; Sandbox hiện tại giữ nguyên chính sách cho đến khi thu hồi.', + egressDefault: 'Chiều ra mặc định', + egressAllowAll: 'Cho phép mạng công cộng (mặc định)', + egressDenyAll: 'Chặn theo mặc định', + egressPrecedence: 'Thứ tự xét duyệt: cho phép, chặn, sau đó đến mặc định. Quy tắc cho phép có mức ưu tiên cao hơn quy tắc chặn.', + allowOut: 'Đích đến được phép', + allowOutPlaceholder: 'Tên miền / IP / CIDR, ví dụ *.example.com', + allowOutHelp: 'Hỗ trợ IPv4, CIDR, tên miền và ký tự đại diện đơn cấp như *.example.com (không khớp với tên miền gốc).', + denyOut: 'Đích đến bị chặn', + denyOutPlaceholder: 'Chỉ chấp nhận IP / CIDR, ví dụ 169.254.169.254/32', + denyOutHelp: 'Quy tắc chặn chỉ đối soát IP đích, không hỗ trợ tên miền.', + domainAllowNeedsDenyAll: 'Khi đích đến được phép có chứa tên miền, cần chọn “Chặn theo mặc định” hoặc thêm 0.0.0.0/0 vào danh sách chặn; nếu không danh sách cho phép sẽ vô hiệu.', + cubeL7Rules: 'Quy tắc truy cập HTTP (L7)', + cubeL7RulesHelp: 'Mỗi quy tắc cần có host hoặc sni; tầng mạng sẽ xác định mục tiêu cho phép dựa trên các trường này. Các trường liên kết theo điều kiện AND, phương thức theo điều kiện OR. Chỉ áp dụng cho HTTP 80 / HTTPS 443. Áp dụng quy tắc khớp đầu tiên từ trên xuống dưới.', + e2bHostRules: 'Chuyển đổi yêu cầu máy chủ', + e2bHostRulesHelp: 'Chèn header theo host. Quy tắc này không tự cấp quyền kết nối ra ngoài; host vẫn phải nằm trong danh sách đích đến được phép.', + ruleUntitled: 'Quy tắc chưa đặt tên', + expandRule: 'Mở rộng quy tắc', + collapseRule: 'Thu gọn quy tắc', + moveRuleUp: 'Di chuyển lên', + moveRuleDown: 'Di chuyển xuống', + ruleName: 'Tên quy tắc', + ruleScheme: 'Giao thức', + ruleSni: 'SNI', + ruleHost: 'Host', + ruleMethods: 'Phương thức HTTP', + rulePath: 'Đường dẫn', + ruleAction: 'Hành động', + ruleAllow: 'Cho phép', + ruleDeny: 'Chặn', + ruleAudit: 'Mức ghi nhật ký', + ruleInject: 'Chèn header', + headerName: 'Tên header', + headerValue: 'Giá trị header', + addTarget: 'Thêm đích đến', + addRule: 'Thêm quy tắc', + addHeader: 'Thêm header', + removeRule: 'Xóa quy tắc', + noConfigs: 'Chưa có Sandbox nào. Agent không có cấu hình sẽ không thể chạy kịch bản kỹ năng.', + identityFieldHint: 'Khi cấu hình đang gắn với các Sandbox hoạt động, không thể thay đổi: loại Sandbox, API endpoint, API key, domain Sandbox, proxy endpoint.', + connectionLockedBySkills: 'Sandbox này đã có kỹ năng. Kết nối, thông tin xác thực và DNS sẽ làm thay đổi bản ghi nhanh kỹ năng, và DNS chỉ áp dụng sau khi dựng lại mẫu. Vui lòng tạo Sandbox mới.', + connectionLockedByInFlight: 'Đang cài đặt hoặc gỡ bỏ kỹ năng. Không thể thay đổi kết nối, thông tin xác thực và DNS cho đến khi hoàn tất.', + viewSandboxes: 'Phiên bản đang chạy', + inventoryTitle: 'Phiên bản đang chạy', + inventoryDrawerDesc: 'Các Sandbox thuộc cấu hình này, kèm các phiên và agent bị ảnh hưởng.', + inventoryFailed: 'Tải thông tin sử dụng Sandbox thất bại', + sandboxCount: 'Sandbox', + sandboxCountUnknown: 'Không xác định (không thể kết nối backend)', + inventoryUnverifiableHint: 'Không thể kết nối backend nên chưa rõ số lượng Sandbox — điều này không đồng nghĩa là không có.', + inventorySessions: 'Phiên', + inventorySessionKind: 'Cuộc trò chuyện', + inventoryEmpty: 'Không có phiên chiếm dụng', + inventoryAgentsTitle: 'Agent liên kết', + inventoryUntitledSession: 'Phiên chưa đặt tên', + sandboxesStillLive: 'Cấu hình này vẫn còn {count} Sandbox đang chạy hoặc tạm dừng, nên chưa thể đổi các trường định danh.', + blockedHint: 'Kết thúc hoặc xóa các phiên này (xóa phiên sẽ hủy Sandbox), hoặc tạo cấu hình thứ hai và trỏ agent sang đó.', + unverifiableBlocked: 'Không thể kết nối backend để kiểm tra Sandbox còn lại, nên thông tin xác thực đã lưu sẽ không bị ghi đè.', + unverifiableSaveHint: 'Khôi phục kết nối trước; nếu backend ngừng hoạt động vĩnh viễn, hãy tạo cấu hình thứ hai và trỏ agent sang đó.', + affectedSessions: 'Ảnh hưởng {count} phiên.', + affectedAgents: 'Agent dùng cấu hình này: {names}', + confirmDelete: 'Xóa Sandbox "{name}"?', + confirmDeleteWithAgents: 'Xóa Sandbox "{name}"? {agents}Các agent này sẽ thất bại trong lần chạy kỹ năng tiếp theo.', + deleteFailed: 'Xóa thất bại', + deleted: 'Đã xóa', + forceDeleteTitle: 'Không thể xác minh việc sử dụng Sandbox', + forceDeleteConfirm: 'Không thể kết nối backend để kiểm tra Sandbox còn lại. Nếu backend đã ngừng hoạt động vĩnh viễn, bạn có thể buộc xóa cấu hình này; nếu chỉ mất kết nối tạm thời, việc buộc xóa sẽ khiến các Sandbox còn lại không thể thu hồi. Vẫn buộc xóa?', + forceDelete: 'Buộc xóa', + disableScripts: 'Tắt thực thi trong Sandbox', + enableScripts: 'Bật thực thi trong Sandbox', + disableScriptsConfirm: 'Mọi agent trong không gian làm việc này sẽ ngừng chạy script kỹ năng trong Sandbox. Agent vẫn có thể đọc nội dung kỹ năng. Các Sandbox từ xa hiện có không tự động bị hủy; hãy kết thúc hoặc xóa phiên liên quan để giải phóng. Tiếp tục?', + scriptsDisabled: 'Đã tắt thực thi trong Sandbox cho không gian làm việc này', + scriptsEnabled: 'Đã bật lại thực thi trong Sandbox cho không gian làm việc này', + policySaveFailed: 'Cập nhật chính sách thực thi Sandbox thất bại', + legacyConfig: 'Không còn dùng', + namedBackendHint: 'Cấu hình không gian làm việc là nguồn runtime duy nhất. Agent không có cấu hình sẽ không thể chạy script kỹ năng.', + weknoraTemplateTitle: 'Mẫu WeKnora chuẩn', + weknoraDockerImage: 'Image WeKnora chuẩn', + weknoraDockerImageHint: 'Mỗi phiên có một container chạy riêng. Script, lệnh shell và tệp dùng chung container này cho đến khi kết thúc phiên hoặc hết thời gian chờ.', + weknoraTemplateOverview: 'WeKnora cung cấp runtime chuẩn. Mẫu được phát hiện sau khi kết nối và mẫu chuẩn sẽ được tạo tự động nếu còn thiếu.', + weknoraTemplateDescription: 'Bao gồm Python, Node.js, công cụ CLI, đường dẫn workspace và người dùng không có quyền root theo yêu cầu của kỹ năng WeKnora.', + recommendedTag: 'Khuyên dùng', + cardTemplateConfigured: 'Đã cấu hình mẫu', + cardCredentialMissing: 'Thiếu khóa API', + cardTimeout: 'Hết thời gian {sec}s', + cardTtl: 'TTL Sandbox {sec}s', + cardVolumeMounted: 'Đã gắn volume', + cardEnvVars: '{count} biến môi trường', + cardPrivateEndpoints: 'Cho phép endpoint nội bộ', + templateNotConfigured: 'Chưa cấu hình mẫu', + imageNotConfigured: 'Chưa cấu hình image', + templateApplied: 'Đã áp dụng', + refreshTemplates: 'Làm mới mẫu', + templateSelectHelp: 'Mẫu được tải từ cụm này. Cấu hình đã lưu sẽ tự động lưu ID.', + templateSelectPlaceholder: 'Kết nối với cụm để tải mẫu', + templateLoadHint: 'Nhập kết nối cụm và làm mới. Mẫu WeKnora CLI bị thiếu sẽ được dựng từ Hub image chính thức. Mẫu Desktop có dung lượng lớn hơn; tạo từ hàng bên dưới. Sau khi đổi DNS hoặc image, hãy dựng lại từ thẻ đó.', + templateLoadFailed: 'Tải mẫu thất bại', + standardTemplateProvisioning: 'Đang tạo mẫu WeKnora chuẩn. Vui lòng làm mới sau giây lát để xem trạng thái.', + standardTemplateReplaced: 'Mẫu chuẩn trước đó đã bị xóa và quá trình dựng lại đã bắt đầu. Vui lòng chờ đến khi sẵn sàng.', + templateNotReady: 'Mẫu đã chọn chưa sẵn sàng. Vui lòng làm mới và đợi quá trình dựng hoàn tất.', + connectionPassed: 'Đã xác minh kết nối. Các mẫu bên dưới được tải từ cụm này.', + connectionPassedTitle: 'Đã kết nối cụm', + templateStepHint: 'Bước này liệt kê các mẫu của cụm và dựng image CLI chính thức nếu bị thiếu. Mẫu Desktop (XFCE) nặng hơn và chỉ được tạo khi bạn nhấn Tạo. Sau khi đổi DNS hoặc image, hãy dựng lại thẻ đó. Bạn có thể tiếp tục khi mẫu đã sẵn sàng.', + loadingTemplates: 'Đang tải mẫu từ cụm...', + templateBuildingHint: 'Mẫu này đang được dựng. Danh sách sẽ tự làm mới.', + templateUntaggedHint: 'Quá trình dựng đã hoàn tất nhưng không có thẻ mặc định, nên việc tạo Sandbox không thể nhận diện mẫu này. Hãy xóa trong E2B và làm mới; WeKnora sẽ dựng lại.', + templateFailedReason: 'Dựng thất bại: {reason}', + noTemplates: 'Cụm này không trả về mẫu nào.', + weknoraStandardTemplate: 'Mẫu WeKnora chuẩn', + createStandardTemplate: 'Tạo', + createStandardTemplateHint: 'Dựng theo cài đặt kết nối hiện tại, bao gồm DNS. Sau khi thay đổi cài đặt này, hãy dựng lại từ thẻ.', + weknoraDesktopTemplate: 'Mẫu WeKnora Desktop', + createDesktopTemplate: 'Tạo', + createDesktopTemplateHint: 'Dựng giao diện đồ họa XFCE từ desktop image chính thức. Dung lượng lớn hơn nhiều so với mẫu CLI; chỉ tạo khi cần GUI.', + replaceStandardTemplate: 'Dựng lại', + replaceStandardTemplateConfirm: 'Dựng lại mẫu WeKnora chuẩn theo cài đặt hiện tại, bao gồm DNS. Mẫu có thể khởi tạo trước đó sẽ không bị xóa cho đến khi mẫu thay thế sẵn sàng.', + desktopTemplateProvisioning: 'Đang tạo mẫu WeKnora Desktop. Vui lòng làm mới sau giây lát để xem trạng thái.', + desktopTemplateReplaced: 'Mẫu Desktop trước đó đã bị xóa và quá trình dựng lại đã bắt đầu. Vui lòng chờ đến khi sẵn sàng. Mẫu CLI không bị ảnh hưởng.', + desktopTemplateTag: 'Desktop', + replaceDesktopTemplateConfirm: 'Dựng lại mẫu WeKnora Desktop theo cài đặt hiện tại, bao gồm DNS. Mẫu desktop có thể khởi tạo trước đó sẽ không bị xóa cho đến khi mẫu thay thế sẵn sàng. Mẫu CLI không bị ảnh hưởng.', + templateLockedBySkills: 'Sandbox này đã có kỹ năng. Môi trường kỹ năng gắn liền với bản ghi nhanh hiện tại, nên không thể thay đổi hoặc dựng lại mẫu runtime. Hãy tạo Sandbox mới và cài đặt kỹ năng từ mẫu mới.', + templateLockedByInFlight: 'Đang cài đặt hoặc gỡ bỏ kỹ năng. Không thể thay đổi hoặc dựng lại mẫu runtime cho đến khi hoàn tất.', + templateUnnamed: 'Mẫu chưa đặt tên', + templateFieldImage: 'Image', + templateFieldVersion: 'Phiên bản', + templateFieldId: 'ID', + templateFieldCreated: 'Đã tạo', + templateFieldInstance: 'Loại phiên bản', + templateFieldNetwork: 'Mạng', + templateFieldInternet: 'Truy cập Internet', + templateInternetOn: 'Bật', + templateInternetOff: 'Tắt', + templateReadyHint: 'Mẫu “{name}” đã sẵn sàng và được chọn.', + templateProvisioningHint: 'Mẫu vẫn đang được dựng. Trạng thái sẽ tự động làm mới.', + templateStatuses: { + ready: 'Sẵn sàng', + building: 'Đang dựng', + untagged: 'Không có thẻ mặc định', + failed: 'Thất bại', + unknown: 'Không xác định' + }, + allowPrivateEndpoints: 'Cho phép endpoint cụm nội bộ', + allowPrivateEndpointsHint: 'Dùng cho control plane riêng tự host. Các địa chỉ link-local và metadata đám mây vẫn bị chặn.', + skillUploadHintNewSession: 'Quá trình cài đặt sẽ ghi kỹ năng vào image hiện tại và tạo snapshot mới trong vài phút. Các phiên đang mở vẫn dùng Sandbox hiện tại cho đến khi kết thúc; chỉ các phiên mới tạo mới áp dụng kỹ năng này.', + skillSourceSection: 'Cài đặt từ nguồn', + skillSourceSectionHint: 'Dán liên kết ClawHub, GitHub, SkillHub hoặc {\'@\'}owner/slug. Dung lượng gói tối đa {size} MB.', + skillUploadSection: 'Tải lên gói cục bộ', + skillUploadSectionHint: 'Kéo thả tệp zip chứa SKILL.md vào đây hoặc nhấp để chọn. Dung lượng tối đa {size} MB.', + skillSourcePlaceholder: 'ClawHub: {\'@\'}owner/slug. GitHub/SkillHub: dán toàn bộ URL', + skillSourceInstall: 'Cài đặt', + skillInstallOr: 'hoặc', + skillSourceFailed: 'Không thể cài đặt kỹ năng từ registry', + skillUploadFailed: 'Tải lên kỹ năng thất bại', + skillBundleTooLarge: 'Gói kỹ năng không được vượt quá {size} MB.', + skillBundleTooManyFiles: 'Thư mục kỹ năng không được chứa quá {count} tệp.', + skillBundleTooManyZipEntries: 'Tệp nén không được chứa quá {count} mục.', + skillUploading: 'Đang tải lên {percent}%', + skillUploadAccepted: 'Đã bắt đầu cài đặt kỹ năng', + skillStatusInstalling: 'Đang cài đặt', + skillStatusReady: 'Sẵn sàng', + skillStatusFailed: 'Thất bại', + skillStatusRemoving: 'Đang gỡ bỏ', + skillStatusLabel: 'Trạng thái', + skillDisableHint: 'Vô hiệu hóa = ẩn kỹ năng với agent, giữ lại tệp trong image. Thay đổi áp dụng từ lượt thực thi tiếp theo của phiên.', + skillDeleteHint: 'Xóa sẽ loại bỏ thư mục kỹ năng khỏi image và tạo snapshot mới. Lượt trò chuyện hiện tại không bị gián đoạn; các phiên mở sẽ dựng lại Sandbox ở lượt tiếp theo và xóa không gian nháp tạm thời.', + skillDeleteHintNewSession: 'Xóa sẽ loại bỏ thư mục kỹ năng khỏi image và tạo snapshot mới. Các phiên đang mở vẫn dùng Sandbox hiện tại đến khi kết thúc; chỉ các phiên mới bắt đầu sẽ mất kỹ năng này.', + skillRemoveInProgress: 'Đang gỡ cài đặt', + skillRemoveWaiting: 'Đã bắt đầu gỡ khỏi image. Đang chờ tiến trình…', + skillRemoveDone: 'Đã gỡ “{name}” khỏi Sandbox này. Kỹ năng vẫn lưu trong danh mục để bạn cài lại sau.', + skillRemoveStage: { + accepted: 'Đã tiếp nhận yêu cầu gỡ cài đặt', + sandbox_ready: 'Đang mở Sandbox bảo trì', + removed: 'Đã xóa tệp, đang dựng image mới', + done: 'Gỡ cài đặt hoàn tất', + failed: 'Gỡ cài đặt thất bại' + }, + imageInfoTitle: 'Image hiện tại', + imageInfoSnapshot: 'ID snapshot', + imageInfoGeneration: 'Phiên bản', + imageInfoBuiltAt: 'Thời gian tạo', + imageInfoBaseTemplate: 'Mẫu cơ sở', + imageInfoRuntimeTemplate: 'Mẫu runtime', + imageInfoUsingBase: 'Chưa cài đặt kỹ năng. Các phiên sẽ khởi động từ mẫu runtime đã chọn.', + imageInfoEmpty: 'Đang dùng mẫu cơ sở', + imageInfoUnset: 'Chưa thiết lập', + skillTranscript: 'Xem tiến trình cài đặt', + skillTranscriptLive: 'Nhật ký cài đặt', + skillTranscriptLiveHint: 'Đang cài đặt — nhấp để xem', + skillTranscriptTitle: 'Tiến trình cài đặt', + skillTranscriptHide: 'Ẩn tiến trình cài đặt', + skillGuidance: { + placeholder: 'Thêm chỉ dẫn cài đặt như CLI cần thiết, tài liệu cấu hình hoặc ràng buộc môi trường', + send: 'Gửi chỉ dẫn', + retry: 'Cài lại kèm chỉ dẫn', + pending: 'Đang chờ', + injected: 'Đã áp dụng', + unprocessed: 'Chưa xử lý; sẽ bao gồm khi cài đặt lại', + unavailable: 'Không thể nhập ở giai đoạn này. Bạn có thể cài lại kèm chỉ dẫn sau khi tiến trình kết thúc.', + failed: 'Không thể gửi chỉ dẫn. Nội dung của bạn vẫn được giữ lại; vui lòng thử lại.' + }, + skillTranscriptEmpty: 'Lần cài đặt này không có nhật ký tiến trình.', + skillTranscriptWaiting: 'Đã bắt đầu cài đặt. Đang chờ nhật ký xử lý…', + installCommandRunning: 'Lệnh đang chạy', + installCommandWaiting: 'Đang chờ kết quả từ lệnh. Thời gian thực thi vẫn tiếp tục đếm.', + skillFiles: 'Xem tệp', + skillFilesTitle: 'Tệp', + skillFilesEmpty: 'Kỹ năng này chưa có tệp để duyệt.', + skillFilesLoadFailed: 'Không thể tải tệp kỹ năng', + skillFilesFileLoadFailed: 'Không thể đọc tệp này', + skillFilesBinary: 'Tệp nhị phân, không thể xem trước.', + skillFilesTruncated: 'Tệp quá lớn; chỉ hiển thị phần đầu.', + skillFilesSelectHint: 'Chọn tệp ở bên trái để xem', + skillFilesPreview: 'Xem trước', + skillFilesSource: 'Mã nguồn', + skillLoadFailed: 'Không thể tải kỹ năng', + skillToggleFailed: 'Cập nhật kỹ năng thất bại', + skillDeleteAccepted: 'Đã bắt đầu xóa kỹ năng', + skillRetry: 'Cài lại', + skillRetryHint: 'Thử lại bằng gói đã lưu; không cần tải lên lại', + skillRetryAccepted: 'Đã bắt đầu cài lại', + skillRetryFailed: 'Không thể bắt đầu cài lại', + skillStop: 'Dừng cài đặt', + skillStopHint: 'Hủy lượt cài đặt này, sau đó thử lại hoặc gỡ bỏ', + skillStopAccepted: 'Đã dừng', + skillStopFailed: 'Không thể dừng', + skillEmpty: 'Chưa có kỹ năng nào. Hãy dán URL registry hoặc tải lên tệp zip.', + skillVersion: 'Phiên bản', + skillVersionEmpty: 'Chưa chỉ định', + skillError: 'Lỗi', + skillEnabled: 'Đã bật kỹ năng', + skillDisabled: 'Đã tắt kỹ năng', + skillEnv: { + toggle: 'Biến môi trường', + toggleHide: 'Ẩn biến môi trường', + none: 'Kỹ năng này không khai báo biến môi trường nào.', + workspaceTitle: 'Giá trị toàn không gian làm việc', + workspaceHint: 'Mọi thành viên chưa cấu hình giá trị riêng sẽ dùng giá trị ở đây. Thành viên tự thiết lập tại Cài đặt → Bí mật Sandbox.', + required: 'Bắt buộc', + isSet: 'Đã thiết lập', + notSet: 'Chưa thiết lập', + placeholderSet: 'Đã lưu, nhập để thay thế', + placeholderUnset: 'Nhập giá trị', + save: 'Lưu', + saveSuccess: 'Đã lưu giá trị cho không gian làm việc', + saveFailed: 'Không thể lưu giá trị không gian làm việc.', + clear: 'Xóa', + clearConfirm: 'Xóa giá trị không gian làm việc của {name}? Định nghĩa biến vẫn được giữ lại. Các thành viên chưa thiết lập giá trị riêng sẽ bị thiếu biến này.', + clearSuccess: 'Đã xóa giá trị không gian làm việc.', + valueTooLong: 'Giá trị không được vượt quá {max} byte.' + }, + howToBuildTemplate: 'Hướng dẫn thiết lập cụm Sandbox và mẫu', + noEnvVars: 'Không có biến môi trường bổ sung.', + fieldRequired: 'Bắt buộc', + cubeApiKeyOptional: 'Không bắt buộc — để trống nếu dùng CubeSandbox tự lưu trữ không yêu cầu xác thực', + cubeApiKeyWhere: 'Cách bật xác thực trên cụm tự lưu trữ', + cubeDnsServers: 'Máy chủ DNS', + cubeDnsServersHelp: 'Không bắt buộc. Địa chỉ IP nameserver được ghi vào mẫu tiêu chuẩn WeKnora. Để trống để dùng mặc định của cụm (thường là 119.29.29.29). Nếu UDP/53 đến resolver công khai bị chặn, hãy dùng địa chỉ hợp lệ từ /etc/resolv.conf của máy chủ Cube, loại trừ 10/8, 172.16/12 và 192.168/16. Các mẫu tiêu chuẩn hiện có chỉ có hiệu lực sau khi nhấn \'Tạo lại\' trên thẻ mẫu.', + cubeDnsServersPlaceholder: 'VD: 8.8.8.8, nhấn Enter để thêm', + e2bApiKeyHelp: 'Tạo tại trang API Keys trên bảng điều khiển E2B; thường bắt đầu bằng e2b_.', + e2bApiKeyWhere: 'Lấy API key từ bảng điều khiển E2B', + apiKeyPlaceholder: 'Dán API key', + secretConfigured: 'Đã cấu hình khóa (không hiển thị lại); nhập giá trị mới để thay thế', + secretKeepHint: 'Đã cấu hình — để trống để giữ nguyên', + e2bApiUrlOptional: 'Không bắt buộc — để trống sẽ dùng mặc định của SDK', + e2bDomainOptional: 'Không bắt buộc — để trống sẽ dùng mặc định của SDK', + e2bProxyUrlOptional: 'Cổng data-plane của cụm tương thích E2B tự lưu trữ. Để trống để kết nối Sandbox qua tên miền Sandbox tương tự E2B Cloud.', + backends: { + disabled: 'Đã tắt', + local: 'Tiến trình cục bộ', + docker: 'Docker', + cube: 'CubeSandbox', + e2b: 'E2B' + }, + apiUrl: 'Endpoint API', + proxyUrl: 'Endpoint proxy', + sandboxDomain: 'Tên miền Sandbox', + apiKey: 'API key', + templateId: 'ID mẫu', + httpTimeout: 'Thời gian chờ HTTP (giây)', + httpTimeoutHelp: 'Thời gian tối đa cho lệnh quản lý tới backend trước khi tính là mất kết nối. Để trống nghĩa là 30 giây.', + sandboxTtl: 'TTL Sandbox (giây)', + sandboxTtlHelp: 'Thời gian trước khi tạm dừng Sandbox', + dockerImage: 'Docker image', + dockerHost: 'Endpoint Docker daemon', + dockerHostHelp: 'Để trống sẽ dùng cấu hình Docker CLI cục bộ (DOCKER_HOST hoặc docker context hiện tại), không cần nhập /var/run/docker.sock. Với daemon từ xa, dùng tcp://host:2376, điền thư mục chứng chỉ TLS và bật tùy chọn cho phép endpoint nội bộ cho dải IP RFC1918.', + dockerTlsCertPath: 'Thư mục chứng chỉ TLS', + dockerTlsCertPathHelp: 'Thư mục trên máy chủ WeKnora chứa ca.pem, cert.pem và key.pem. Bắt buộc với daemon từ xa; chứng chỉ được gắn qua triển khai, không lưu trữ tại đây.', + dockerIdleTtl: 'Thu hồi khi nhàn rỗi (giây)', + dockerIdleTtlHelp: 'Docker daemon không tự ngắt khi nhàn rỗi. Container không chạy lệnh trong khoảng thời gian này sẽ được WeKnora thu hồi và tạo lại khi tiếp tục phiên. Để trống nghĩa là 1800 giây.', + dockerCpuLimit: 'Số nhân CPU', + dockerCpuLimitHelp: 'Số nhân CPU cấp cho mỗi Sandbox; 0 là dùng mặc định hệ thống.', + dockerMemoryLimit: 'Giới hạn bộ nhớ (MB)', + dockerMemoryLimitHelp: 'Giới hạn RAM (MB) cho mỗi Sandbox; 0 là dùng mặc định hệ thống.', + dockerPidsLimit: 'Giới hạn tiến trình', + dockerPidsLimitHelp: 'Số tiến trình tối đa một Sandbox có thể tạo; 0 là dùng mặc định hệ thống.', + dockerNetworkMode: 'Chế độ mạng', + dockerNetworkModeHelp: 'Mặc định là bridge, cần thiết để kỹ năng cài đặt các gói. Chọn none để ngắt hoàn toàn kết nối ra ngoài. Docker chỉ lọc theo mạng; không hỗ trợ quy tắc theo từng tên miền tại đây.', + dockerNetworkBridge: 'bridge (cho phép truy cập ra ngoài)', + dockerNetworkNone: 'none (không có mạng)', + defaultTimeout: 'Thời gian chờ thực thi (giây)', + defaultTimeoutHelp: 'Thời gian tối đa một script kỹ năng được chạy trước khi bị dừng. Để trống nghĩa là 60 giây.', + terminalIdleDisconnect: 'Ngắt terminal / desktop khi nhàn rỗi (giây)', + terminalIdleDisconnectHelp: 'Tự động đóng terminal hoặc desktop sau thời gian này nếu không có tương tác để Sandbox tạm dừng theo TTL. Terminal tính thao tác phím và đầu ra PTY; desktop tính chuột và bàn phím. Để trống nghĩa là 900 giây; tối thiểu 60 giây, tối đa 24 giờ.', + envVars: 'Biến môi trường', + envKey: 'Tên biến', + envValue: 'Giá trị', + envVarsHint: 'Được nạp vào mọi Sandbox tạo từ cấu hình này. Giá trị được mã hóa khi lưu trữ nhưng script trong Sandbox vẫn có thể đọc được.\nChỉ nạp khi khởi tạo Sandbox; để nạp ở mỗi lượt chạy, hãy thêm tại trang Khóa bí mật Sandbox.', + addRow: 'Thêm biến', + removeRow: 'Xóa', + save: 'Lưu', + saveAndContinue: 'Lưu và tiếp tục', + saved: 'Đã lưu. Áp dụng cho các phiên mới.', + saveFailed: 'Lưu thất bại', + testConnection: 'Kiểm tra kết nối', + deepCheck: 'Kiểm tra toàn diện', + recheck: 'Kiểm tra lại', + deepCheckIntro: 'Kiểm tra toàn diện sẽ tạo Sandbox tạm, chạy thử một script, kiểm tra kết nối mạng ra ngoài và hủy Sandbox.', + deepCheckConfirm: 'Kiểm tra toàn diện sẽ chạy thử một script. Backend từ xa cũng sẽ khởi tạo và hủy một Sandbox thực tế, có thể tiêu tốn một lượng nhỏ tài nguyên sử dụng. Tiếp tục?', + checkPassed: 'Tất cả kiểm tra đều đạt', + checkFailed: 'Một số kiểm tra thất bại', + checkScopeConnection: 'Chỉ kiểm tra control plane: endpoint phản hồi và thông tin xác thực hợp lệ. Chưa kiểm tra khả năng chạy script thực tế.', + checkScopeFull: 'Endpoint, thông tin xác thực, mẫu, khả năng thực thi trong Sandbox và kết nối mạng ra ngoài đều đã được xác minh thực tế.', + checkScopePolicyRestricted: 'Truy cập mạng ra ngoài bị giới hạn theo chính sách nên không kiểm tra egress. Endpoint, thông tin xác thực, mẫu và khả năng thực thi trong Sandbox đã được xác minh.', + checkPendingHint: 'Chỉ có thể xác nhận {names} qua kiểm tra toàn diện: tạo Sandbox tạm, chạy script thử nghiệm và hủy Sandbox.', + skipReasons: { + needs_deep_check: 'Cần kiểm tra toàn diện', + control_plane_unreachable: 'Đã bỏ qua: không kết nối được control plane', + sandbox_not_created: 'Đã bỏ qua: không tạo được Sandbox', + sandbox_exec_failed: 'Đã bỏ qua: thực thi trong Sandbox thất bại', + egress_restricted_by_policy: 'Bị hạn chế bởi chính sách mạng (cấu hình này mặc định chặn kết nối ra ngoài)' + }, + checks: { + client_build: 'Khởi tạo client', + api_url_reachable: 'Kết nối endpoint', + credential_valid: 'Thông tin xác thực hợp lệ', + template_exists: 'Mẫu tồn tại', + sandbox_exec: 'Thực thi trong Sandbox', + egress_available: 'Mạng kết nối ra ngoài' + }, + manageSkills: 'Quản lý kỹ năng', + cardSkillsNone: 'Chưa cài đặt kỹ năng', + cardSkillsMore: '+{count}', + skillInstallerModel: 'Mô hình cài đặt', + skillInstallerModelHint: 'Được dùng bởi agent cài đặt tích hợp. Hãy chọn mô hình trò chuyện hỗ trợ gọi công cụ (tool calls).', + skillInstallerModelRequired: 'Vui lòng chọn mô hình cài đặt trước', + skillInstallerModelSaveFailed: 'Lưu mô hình cài đặt thất bại', + skillRollout: 'Cơ chế áp dụng image kỹ năng mới', + skillRolloutHint: 'Cài đặt hoặc xóa kỹ năng sẽ tạo một image mới. Tùy chọn này xác định các phiên đang mở có chuyển sang dùng image mới hay không.', + skillRolloutNextTurn: 'Dựng lại các phiên đang mở ở lượt chat tiếp theo', + skillRolloutNewSession: 'Giữ nguyên Sandbox cho các phiên đang mở; chỉ phiên mới dùng image mới', + skillRolloutSaveFailed: 'Lưu cấu hình áp dụng thất bại', + skillInstallGroup: 'Cài đặt kỹ năng mới', + skillInstalledGroup: 'Đã cài đặt', + skillUploadClick: 'Nhấp để tải lên tệp zip', + skillUploadDrag: 'hoặc kéo thả tệp vào đây', + skillUploadHint: 'Quá trình cài đặt sẽ ghi kỹ năng vào image hiện tại và tạo bản snapshot mới. Quá trình này có thể mất vài phút. Lượt chat hiện tại không bị gián đoạn; các phiên đang mở sẽ dựng lại Sandbox ở lượt chat tiếp theo, đồng thời xóa dữ liệu tạm trong không gian làm việc của phiên.' + }, + skills: { + title: 'Quản lý kỹ năng', + description: 'Kỹ năng nằm trong danh mục không gian làm việc. Đăng ký trước, sau đó cài đặt vào một hoặc nhiều Sandbox. Agent chỉ có thể bật kỹ năng đã sẵn sàng trên Sandbox của mình.', + helpTooltip: 'Kỹ năng trong danh mục không bắt buộc phải cài đặt ngay. Script chỉ chạy khi kỹ năng đã cài vào image Sandbox của agent. Image của Docker, Cube và E2B không thể dùng chung — cần cài riêng cho từng Sandbox.', + goSandboxSettings: 'Cấu hình Sandbox', + noConfigsDesc: 'Chưa có Sandbox. Kỹ năng cần một image để cài đặt.', + addSkill: 'Thêm kỹ năng', + addDrawerDesc: 'Dán nguồn hoặc tải lên tệp zip để thêm vào danh mục. Bạn có thể cài vào Sandbox ngay bây giờ hoặc sau.', + addProgress: 'Tiến trình thêm', + addStepRegister: 'Đăng ký', + addStepInstall: 'Cài đặt', + addStepRegisterDesc: 'Dán nguồn hoặc tải lên tệp zip để thêm kỹ năng vào danh mục không gian làm việc.', + addStepInstallDesc: 'Xác nhận kỹ năng đã phân tích, sau đó chọn Sandbox để cài đặt. Bạn có thể bỏ qua và cài sau từ danh sách.', + addFinish: 'Hoàn tất', + addRegisteredAs: 'Đã đăng ký dưới tên “{name}”', + addFileSelected: 'Đã chọn {name}', + addClearFile: 'Xóa', + emptyDesc: 'Chưa có kỹ năng nào. Hãy thêm kỹ năng rồi cài đặt vào một hoặc nhiều Sandbox.', + emptyNoSandboxHint: 'Chưa có Sandbox nào. Kỹ năng dạng script không thể chạy cho đến khi được cài vào image.', + installSkill: 'Thêm kỹ năng', + installDrawerDesc: 'Cài đặt vào image {name}.', + installToSandbox: 'Cài vào Sandbox', + installToSandboxDesc: 'Mỗi nền tảng Sandbox cần cài đặt riêng. Image của Docker, Cube và E2B không thể dùng chung.', + pickSandboxes: 'Cài vào Sandbox', + pickSandboxesHint: 'Kỹ năng sẽ được ghi vào image của từng Sandbox đã chọn. Image của Docker, Cube và E2B không thể dùng chung — cần cài riêng cho từng Sandbox. Bạn có thể bỏ qua và cài sau từ danh mục.', + noSandboxToInstall: 'Không có Sandbox khả dụng để cài đặt.', + noInstalls: 'Chưa cài trên Sandbox nào', + installedOn: 'Đã cài trên', + installedOnName: 'Đã cài trên {name}', + installedCount: 'Đã cài trên {count} Sandbox', + installPanelGroup: 'Đã cài đặt', + installPanelAvailable: 'Chưa cài đặt', + viewInstallProgress: 'Xem tiến trình', + manageOnSandbox: 'Quản lý kỹ năng này trên “{name}”', + manageDrawerDesc: 'Quản lý kích hoạt, biến môi trường và gỡ cài đặt trên Sandbox “{name}”.', + manageEnable: 'Bật', + manageUninstall: 'Gỡ khỏi Sandbox', + manageUninstallConfirm: 'Gỡ bỏ “{name}” khỏi Sandbox này?', + deleteCatalog: 'Xóa khỏi danh mục', + deleteCatalogConfirm: 'Xóa “{name}” khỏi danh mục? Vui lòng gỡ cài đặt khỏi tất cả Sandbox trước.', + deleteCatalogBlocked: 'Cần gỡ cài đặt kỹ năng này khỏi tất cả Sandbox trước.', + deleteSuccess: 'Đã xóa khỏi danh mục', + registerAccepted: 'Đã thêm vào danh mục', + installAccepted: 'Đã bắt đầu cài đặt', + installPartial: 'Đã bắt đầu trên một số Sandbox. Không thể khởi chạy trên {failed} Sandbox.', + installOutdated: 'Khác với danh mục', + upgrade: 'Nâng cấp', + upgradeCount: 'Nâng cấp {count}', + upgradeTitle: 'Nâng cấp kỹ năng', + upgradeDrawerDesc: 'Nâng cấp {name} trên các Sandbox đã chọn lên phiên bản trong danh mục. Mỗi Sandbox tiếp tục chạy phiên bản hiện tại cho đến khi nâng cấp hoàn tất; nếu thất bại, phiên bản cũ vẫn được giữ nguyên.', + upgradeAvailable: 'Có bản nâng cấp', + upgradeFromTo: 'Nâng cấp {from} → {to}', + upgradeAccepted: 'Đã bắt đầu nâng cấp', + noSandboxToUpgrade: 'Không có Sandbox nào cần nâng cấp.', + upgradeRowTitle: 'Có phiên bản mới', + upgradeRowHint: 'Sandbox này đang chạy phiên bản khác với danh mục. Phiên bản hiện tại sẽ tiếp tục chạy cho đến khi nâng cấp xong; nếu thất bại, bản cũ vẫn được giữ nguyên.', + upgradeRowHintVersions: 'Sandbox này đang chạy {from}; danh mục hiện có {to}. Bản {from} tiếp tục chạy cho đến khi nâng cấp xong; nếu thất bại, bản cũ vẫn được giữ nguyên.', + upgradeRowHintFailed: 'Cài đặt trên Sandbox này không thành công và danh mục đã có cập nhật mới. Nâng cấp sẽ cài phiên bản mới nhất từ danh mục.', + upgradeRowHintFailedVersions: 'Cài đặt {from} trên Sandbox này thất bại, hiện danh mục đã có {to}. Nâng cấp sẽ cài đặt {to}.', + servedWhileUpgrading: 'Đang nâng cấp; vẫn chạy {version}', + servedWhileUpgradingPlain: 'Đang nâng cấp; vẫn chạy phiên bản trước', + servedAfterFailure: 'Nâng cấp thất bại; vẫn chạy {version}', + servedAfterFailurePlain: 'Nâng cấp thất bại; vẫn chạy phiên bản trước', + loadFailed: 'Tải thất bại', + hostTarget: 'Máy chủ này', + host: { + description: 'Kỹ năng nằm trong danh mục không gian làm việc. Agent có thể kích hoạt kỹ năng sau khi được cài đặt trên máy chủ này.', + helpTooltip: 'Kỹ năng trong danh mục có thể giữ trạng thái chưa cài đặt. Mã thực thi chỉ chạy sau khi kỹ năng được cài đặt trên máy chủ này.', + emptyDesc: 'Chưa có kỹ năng nào. Thêm kỹ năng mới để có thể cài đặt trên máy chủ này.', + addStepInstallDesc: 'Xác nhận kỹ năng đã phân tích, sau đó chọn mô hình cài đặt. Kỹ năng sẽ được cài đặt trên máy chủ này.', + installToSandbox: 'Cài đặt trên máy chủ này', + installToSandboxDesc: 'Quá trình cài đặt sẽ chuẩn bị các phần phụ thuộc trên máy chủ này. Agent có thể sử dụng kỹ năng ngay khi sẵn sàng.', + installDrawerDesc: 'Cài đặt “{name}” trên máy chủ này.', + noInstalls: 'Chưa cài đặt trên máy chủ này', + installedOnName: 'Đã cài đặt trên máy chủ này', + manageDrawerDesc: 'Kích hoạt, chỉnh sửa biến hoặc gỡ cài đặt trên máy chủ này.', + manageUninstall: 'Gỡ cài đặt khỏi máy chủ này', + manageUninstallConfirm: 'Gỡ cài đặt “{name}” khỏi máy chủ này?', + deleteCatalogConfirm: 'Xóa “{name}” khỏi danh mục? Hãy gỡ cài đặt khỏi máy chủ này trước.', + deleteCatalogBlocked: 'Hãy gỡ cài đặt kỹ năng này khỏi máy chủ trước.', + upgradeDrawerDesc: 'Nâng cấp “{name}” lên phiên bản danh mục. Máy chủ này giữ phiên bản hiện tại cho đến khi nâng cấp hoàn tất; nâng cấp thất bại sẽ giữ nguyên phiên bản cũ.', + disableHint: 'Khi bị vô hiệu hóa, Agent không thể nhìn thấy kỹ năng này. Các tệp vẫn lưu trên máy chủ này. Thay đổi áp dụng ở phiên chạy kế tiếp.', + removeDone: 'Đã gỡ cài đặt “{name}” khỏi máy chủ này. Kỹ năng vẫn lưu trong danh mục và có thể cài đặt lại.', + removeWaiting: 'Đang bắt đầu gỡ cài đặt. Đang chờ tiến trình…', + removeSandboxReady: 'Đang chuẩn bị thư mục cục bộ', + removeRemoved: 'Đã xóa các tệp', + envWorkspaceHint: 'Thành viên chưa đặt giá trị riêng sẽ dùng giá trị này. Họ có thể thiết lập giá trị cá nhân tại Cài đặt → Biến môi trường.' + } + }, + mcpService: 'Dịch vụ MCP', + versionInfo: 'Thông tin phiên bản', + taskQueue: 'Hàng đợi tác vụ', + tenantInfo: 'Thông tin không gian làm việc', + workspaceSettings: 'Cài đặt không gian làm việc', + navGroups: { + account: 'Tài khoản', + workspace: 'Không gian làm việc', + modelsRuntime: 'Mô hình', + dataExtensions: 'Dữ liệu & Tiện ích mở rộng', + systemAdministration: 'Quản trị hệ thống', + platform: 'Nền tảng' + }, + roleDenied: { + title: 'Không đủ quyền truy cập', + desc: 'Vai trò của bạn không thể truy cập trang cài đặt này. Hãy liên hệ quản trị viên không gian làm việc để được cấp quyền.' + }, + capabilityUnavailable: 'Tính năng này không được hỗ trợ trong bản triển khai hiện tại. Bạn đã được chuyển về trang khả dụng.', + weknoraCloud: { + title: 'WeKnora Cloud', + description: 'Cấu hình thông tin xác thực APPID và APPSECRET cho WeKnora Cloud. Thông tin này được dùng cho các dịch vụ mô hình và công cụ phân tích tài liệu.', + viewDocs: 'Xem tài liệu', + unconfigured: 'Chưa cấu hình xác thực. Vui lòng nhập APPID và APPSECRET.', + configured: 'Thông tin xác thực đã được cấu hình và hoạt động bình thường.', + expired: 'Thông tin xác thực WeKnora Cloud đã hết hạn', + expiredDefault: 'Khóa mã hóa đã thay đổi sau khi khởi động lại dịch vụ. Không thể giải mã thông tin xác thực đã lưu. Vui lòng nhập lại.', + reconfigure: 'Cấu hình lại', + appIdLabel: 'APPID', + appIdDesc: 'ID ứng dụng WeKnora Cloud', + appIdPlaceholder: 'Nhập APPID', + appSecretLabel: 'APPSECRET', + appSecretDesc: 'Khóa bí mật ứng dụng WeKnora Cloud', + appSecretPlaceholder: 'Nhập APPSECRET', + saveHint: 'Thông tin xác thực sẽ được xác thực và mã hóa trước khi lưu.', + saveBtn: 'Lưu thông tin xác thực', + usageTitle: 'Hướng dẫn sử dụng', + usageSteps: '1. Lưu APPID và APPSECRET\n2. Đăng ký chat, embedding, rerank và vlm trong mục Mô hình đám mây bên dưới\n3. Trình phân tích: Cài đặt kho tri thức → Động cơ phân tích → WeKnora Cloud', + fillRequired: 'Vui lòng điền APPID và APPSECRET', + saveSuccess: 'Lưu thông tin xác thực thành công', + saveFailed: 'Lưu thông tin xác thực thất bại', + credentialConfigured: 'Đã cấu hình thông tin xác thực WeKnora Cloud.', + credentialExpired: 'Thông tin xác thực đã hết hạn. Vui lòng cấu hình lại.', + credentialUnconfigured: 'Chưa cấu hình thông tin WeKnoraCloud. Vui lòng thiết lập APPID và APPSECRET trước.', + checkingStatus: 'Đang kiểm tra trạng thái xác thực...', + goToSettings: 'Đến Cài đặt', + modelHintConfigured: 'Đã cấu hình thông tin WeKnoraCloud. Xem danh sách mô hình hỗ trợ tại', + modelHintDocsLink: 'Tài liệu API', + modelsSection: { + title: 'Mô hình đám mây', + descReady: 'Đăng ký 4 mô hình chuẩn của WeKnora Cloud cho trò chuyện, truy xuất, Rerank và thị giác.', + descPending: 'Lưu thông tin xác thực ở trên trước khi thêm mô hình đám mây tại đây.', + statusAdded: 'Đã thêm', + statusPending: 'Chưa có thông tin xác thực', + addOne: 'Thêm', + addAllBtn: 'Thêm tất cả còn thiếu ({count})', + addAllConfirm: 'Xác nhận', + confirmAddOne: 'Thêm mô hình {type} "{name}"?', + confirmAddAll: 'Thêm đồng thời toàn bộ {count} mô hình đám mây còn thiếu?', + allReady: 'Cả 4 mô hình đám mây đã sẵn sàng' + }, + addModelsSuccess: 'Đã thêm thành công {count} mô hình', + addModelsPartial: 'Đã thêm {success}, thất bại {failed}', + addModelsFailed: 'Thêm mô hình thất bại', + addModelsEmbeddingFailed: 'Kiểm tra kết nối embedding thất bại; không thể xác định số chiều vector', + addModelsDisplayName: { + chat: 'WeKnoraCloud Chat', + embedding: 'WeKnoraCloud Embedding', + rerank: 'WeKnoraCloud ReRank', + vllm: 'WeKnoraCloud Vision' + } + }, + storageBackend: { + testConnection: 'Kiểm tra kết nối', + localStorage: 'Bộ lưu trữ cục bộ', + setDefault: 'Đặt làm mặc định', + edit: 'Chỉnh sửa', + delete: 'Xóa', + testSuccess: 'Kết nối thành công', + testFailed: 'Kết nối thất bại', + nameRequired: 'Vui lòng nhập tên', + saveSuccess: 'Lưu thành công', + saveFailed: 'Lưu thất bại', + defaultUpdated: 'Đã cập nhật bộ lưu trữ mặc định', + deleteTitle: 'Xóa phiên bản lưu trữ', + deleteConfirm: 'Bạn có chắc chắn muốn xóa "{name}"?', + deleted: 'Đã xóa', + deleteFailed: 'Xóa thất bại', + description: 'Quản lý các bộ lưu trữ cho tệp và hình ảnh; có thể cấu hình nhiều bộ lưu trữ cùng loại.', + empty: 'Chưa có bộ lưu trữ nào được cấu hình', + defaultTag: 'Mặc định', + add: 'Thêm bộ lưu trữ', + editTitle: 'Chỉnh sửa bộ lưu trữ', + createTitle: 'Thêm bộ lưu trữ', + editSubtitle: 'Cập nhật cấu hình kết nối của bộ lưu trữ này.', + createSubtitle: 'Thêm bộ lưu trữ mới cho tệp và hình ảnh.', + basicSection: 'Thông tin cơ bản', + nameLabel: 'Tên', + namePlaceholder: 'vd: COS Production, COS Archive', + providerLabel: 'Loại lưu trữ', + modeLabel: 'Chế độ triển khai', + modeRemote: 'Phiên bản từ xa', + modeEnv: 'Biến môi trường', + connectionSection: 'Cài đặt kết nối', + optionalPlaceholder: 'Tùy chọn', + advancedSection: 'Tùy chọn nâng cao', + pathPrefixLabel: 'Tiền tố đường dẫn', + useSslDesc: 'Truy cập MinIO qua HTTPS', + forcePathStyleDesc: 'Sử dụng Path Style', + useTempBucketDesc: 'Sử dụng bucket tạm thời', + tempBucketLabel: 'Bucket tạm thời', + tempBucketPlaceholder: 'Tùy chọn, dùng cho các tệp tạm', + tempRegionLabel: 'Khu vực bucket tạm thời', + tempRegionPlaceholder: 'Để trống để dùng chung khu vực chính' + }, + storage: { + title: 'Công cụ lưu trữ', + description: 'Cấu hình lưu trữ tài liệu và hình ảnh. Thiết lập thông số tại đây; kho tri thức chỉ cần chọn công cụ sử dụng.', + basicSection: 'Cơ bản', + modeSection: 'Chế độ triển khai', + credentialsSection: 'Thông tin xác thực', + bucketSection: 'Bucket', + useSslDesc: 'Kết nối với MinIO qua HTTPS', + loading: 'Đang tải...', + retry: 'Thử lại', + defaultEngine: 'Công cụ mặc định', + defaultEngineDesc: 'Công cụ lưu trữ mặc định khi tạo kho tri thức mới', + engineLocal: 'Cục bộ', + engineCos: 'Tencent Cloud COS', + engineTos: 'Volcengine TOS', + engineOss: 'Alibaba Cloud OSS', + localTitle: 'Lưu trữ cục bộ', + localDesc: 'Lưu trữ tệp trên hệ thống tệp cục bộ của máy chủ, chỉ phù hợp triển khai nút đơn.', + available: 'Khả dụng', + needsConfig: 'Cần cấu hình', + configurable: 'Có thể cấu hình', + pathPrefix: 'Tiền tố đường dẫn (tùy chọn)', + pathPrefixPlaceholder: 'vd: weknora/images', + prefixPlaceholder: 'vd: weknora', + bucketName: 'Tên bucket', + bucketPlaceholder: 'Tên bucket', + minioDesc: 'Lưu trữ đối tượng tự lưu trữ tương thích S3, phù hợp cho mạng nội bộ và đám mây riêng tư.', + minioDocker: 'Triển khai Docker', + minioRemote: 'MinIO từ xa', + minioDockerDetected: 'Đã phát hiện biến môi trường MinIO triển khai qua Docker. Thông tin kết nối được lấy tự động, không cần nhập thủ công.', + minioDockerNotDetected: 'Không tìm thấy biến môi trường MinIO (MINIO_ENDPOINT,...). Vui lòng kiểm tra lại cấu hình Docker Compose.', + minioRemoteHint: 'Kết nối với dịch vụ MinIO từ xa. Cần nhập thông tin kết nối thủ công.', + cosTitle: 'Tencent Cloud COS', + cosDesc: 'Lưu trữ đối tượng Tencent Cloud, phù hợp triển khai đám mây công cộng kèm tăng tốc CDN.', + cosSecretIdPlaceholder: 'SecretId API Tencent Cloud', + cosSecretKeyPlaceholder: 'SecretKey API Tencent Cloud', + cosAppIdPlaceholder: 'AppID tài khoản Tencent Cloud', + tosTitle: 'Volcengine TOS', + tosDesc: 'Dịch vụ lưu trữ đối tượng Volcengine (TOS), phù hợp triển khai đám mây công cộng.', + tosAccessKeyPlaceholder: 'Access Key của Volcengine', + tosSecretKeyPlaceholder: 'Secret Key của Volcengine', + s3Title: 'AWS S3', + s3Desc: 'AWS S3 và các dịch vụ lưu trữ đối tượng tương thích S3, phù hợp triển khai đám mây công cộng.', + s3AccessKeyPlaceholder: 'AWS Access Key', + s3SecretKeyPlaceholder: 'AWS Secret Key', + s3DefaultCredentialsHint: 'Để trống cả hai khóa để dùng chuỗi xác thực mặc định của AWS (IAM role, IRSA / web identity, biến môi trường hoặc shared config).', + s3EndpointPlaceholder: 'Tùy chọn; để trống để dùng endpoint khu vực của AWS', + ks3Title: 'Kingsoft Cloud KS3', + ks3Desc: 'Dịch vụ lưu trữ đối tượng Kingsoft Cloud (KS3), phù hợp triển khai đám mây công cộng.', + ks3AccessKeyPlaceholder: 'Kingsoft Cloud Access Key', + ks3SecretKeyPlaceholder: 'Kingsoft Cloud Secret Key', + ks3EndpointPlaceholder: 'vd: ks3-cn-beijing.ksyuncs.com', + ks3RegionPlaceholder: 'vd: BEIJING', + engineKs3: 'Kingsoft Cloud KS3', + obsTitle: 'Huawei Cloud OBS', + obsDesc: 'Dịch vụ lưu trữ đối tượng Huawei Cloud (OBS), phù hợp triển khai đám mây công cộng.', + obsAccessKeyPlaceholder: 'Huawei Cloud Access Key', + obsSecretKeyPlaceholder: 'Huawei Cloud Secret Key', + obsEndpointPlaceholder: 'vd: obs.cn-north-4.myhuaweicloud.com', + obsRegionPlaceholder: 'vd: cn-north-4', + engineObs: 'Huawei Cloud OBS', + ossTitle: 'Alibaba Cloud OSS', + ossDesc: 'Dịch vụ lưu trữ đối tượng Alibaba Cloud (OSS), phù hợp triển khai đám mây công cộng.', + ossAccessKeyPlaceholder: 'Alibaba Cloud Access Key', + ossSecretKeyPlaceholder: 'Alibaba Cloud Secret Key', + console: 'Bảng điều khiển', + docs: 'Tài liệu', + testConnection: 'Kiểm tra kết nối', + loadFailed: 'Tải thất bại', + saveSuccess: 'Lưu thành công', + saveFailed: 'Lưu thất bại', + unknownError: 'Lỗi không xác định', + requestFailed: 'Yêu cầu thất bại' + }, + system: 'Cài đặt hệ thống', + parser: { + title: 'Công cụ phân tích', + description: 'Trạng thái và cấu hình công cụ phân tích tài liệu. Cài đặt tại đây được ưu tiên hơn biến môi trường. Để trống để sử dụng giá trị mặc định của biến môi trường.', + supportedFileTypes: 'Định dạng hỗ trợ', + statusSection: 'Trạng thái', + configSection: 'Cấu hình', + featuresLabel: 'Tính năng', + loading: 'Đang tải...', + retry: 'Thử lại', + noEngineDetected: 'Không tìm thấy công cụ phân tích. Vui lòng đảm bảo dịch vụ DocReader đang hoạt động.', + disconnected: 'Mất kết nối', + connected: 'Đã kết nối', + available: 'Khả dụng', + unavailable: 'Không khả dụng', + builtinDesc: 'Công cụ phân tích tích hợp DocReader (docx/pdf/xlsx và các định dạng phức tạp khác)', + currentAddr: 'Hiện tại', + envVarHint: 'Để sửa đổi, hãy thiết lập các biến môi trường DOCREADER_ADDR và DOCREADER_TRANSPORT (grpc/http), sau đó khởi động lại dịch vụ.', + selfHostedEndpoint: 'Endpoint tự lưu trữ', + formulaRecognition: 'Nhận diện công thức', + tableRecognition: 'Nhận diện bảng', + parseMethodLabel: 'Phương thức phân tích PDF', + parseMethodAuto: 'Tự động phát hiện (Khuyên dùng)', + parseMethodOCR: 'Bắt buộc OCR', + parseMethodText: 'Chỉ trích xuất văn bản', + parseMethodHint: 'Chế độ tự động sẽ dùng OCR cho bản scan và trích xuất lớp văn bản gốc cho PDF kỹ thuật số.', + sealRecognition: 'Nhận diện con dấu', + chartRecognition: 'Nhận diện biểu đồ', + language: 'Ngôn ngữ', + testConnection: 'Kiểm tra kết nối', + docs: 'Tài liệu', + loadFailed: 'Không thể tải danh sách công cụ phân tích', + ensureDocreaderConnected: 'Vui lòng đảm bảo dịch vụ DocReader đã được cấu hình qua biến môi trường và kết nối thành công', + checkDoneStatusUpdated: 'Đã kiểm tra với tham số hiện tại. Trạng thái phía trên đã được cập nhật.', + checkSuccess: 'Kiểm tra kết nối thành công', + checkFailed: 'Kiểm tra thất bại', + saveSuccess: 'Lưu thành công', + saveFailed: 'Lưu thất bại', + mineruEndpointPlaceholder: 'vd: https://your-mineru.example.com', + defaultPipeline: 'Quy trình mặc định', + languagePlaceholder: 'vd: ch, en, ja (mặc định ch)', + mineruCloudApiKeyPlaceholder: 'Khóa API MinerU Cloud', + vlmLabel: 'vlm (Mô hình ngôn ngữ - thị giác)', + mineruHtmlLabel: 'MinerU-HTML (Phân tích HTML)', + serverUrl: 'URL máy chủ', + vlmServerUrlPlaceholder: 'vd: http://your-vllm-server:8000', + vlmServerUrlHint: 'Bắt buộc khi Backend là vlm-http-client hoặc hybrid-http-client', + paddleocrVlEndpointPlaceholder: 'vd: http://your-paddleocr-vl:8080', + paddleocrVlEndpointHint: 'URL gốc của dịch vụ pipeline PaddleOCR-VL; không cần hậu tố /layout-parsing', + paddleocrVlCloudTokenPlaceholder: 'PaddleOCR-VL AI Studio Token', + mineruEndpointHint: 'Phiên bản máy chủ được tự động nhận diện: MinerU 4.0+ sử dụng API V1, các phiên bản cũ hơn sử dụng /file_parse.', + mineruServerApiKeyPlaceholder: 'Giá trị của cờ --api-key máy chủ (để trống nếu tắt xác thực)', + mineruServerApiKeyHint: 'Chỉ áp dụng cho MinerU 4.0+.', + mineruTierLabel: 'Phân cấp bóc tách', + mineruTierDefault: 'Mặc định máy chủ (ưu tiên standard)', + mineruTierFlash: 'flash (nhanh nhất, chất lượng thấp nhất)', + mineruTierBasic: 'basic (mô hình nhỏ, chạy trên CPU)', + mineruTierStandard: 'standard (VLM, chất lượng cao)', + mineruTierAdvanced: 'advanced (VLM, chất lượng cao nhất, chậm nhất)', + mineruTierHint: 'Chỉ áp dụng cho MinerU 4.0+; các phân cấp khả dụng phụ thuộc vào cờ --tier của máy chủ.', + mineruLegacySection: 'Tùy chọn cũ (MinerU 3.x trở về trước)', + mineruLegacySectionHint: 'MinerU 4.0 đã loại bỏ các tham số yêu cầu này nên máy chủ 4.0+ sẽ bỏ qua; hãy cấu hình máy chủ VLM trực tiếp trên MinerU.' + } + }, + webSearchSettings: { + title: 'Cấu hình tìm kiếm web', + description: 'Cấu hình tìm kiếm web để câu trả lời có thể cập nhật thông tin mới nhất từ internet.', + basicSection: 'Cơ bản', + credentialsSection: 'Kết nối', + optionsSection: 'Tùy chọn', + providersTitle: 'Nhà cung cấp công cụ tìm kiếm', + addProvider: 'Thêm nhà cung cấp', + editProvider: 'Chỉnh sửa nhà cung cấp', + deleteConfirm: 'Bạn có chắc chắn muốn xóa nhà cung cấp này?', + providerNameLabel: 'Tên', + providerNamePlaceholder: 'vd: Bing Search Production', + providerTypeLabel: 'Loại nhà cung cấp', + providerDescLabel: 'Ghi chú', + providerDescPlaceholder: 'Tùy chọn, vd: để thử nghiệm', + engineIdLabel: 'Engine ID', + setAsDefault: 'Đặt làm mặc định', + testConnection: 'Kiểm tra kết nối', + testing: 'Đang kiểm tra...', + viewDocs: 'Xem tài liệu lấy API key', + noProvidersDesc: 'Thêm nhà cung cấp tìm kiếm web để agent có thể truy xuất thông tin thời gian thực từ internet.', + setAsDefaultDesc: 'Được dùng mặc định khi agent không chỉ định nhà cung cấp cụ thể', + proxyUrlLabel: 'HTTP proxy', + proxyUrlPlaceholder: 'Vd: http://proxy.example.com:3128 (tùy chọn; chỉ http/https)', + proxyUrlHelp: 'Dùng khi truy cập ra API tìm kiếm cần qua proxy; để trống nếu dùng biến môi trường HTTP_PROXY/HTTPS_PROXY.', + apiKeyLabel: 'API Key', + apiKeyOptionalLabel: 'API Key (tùy chọn)', + baseUrlLabel: 'URL instance', + baseUrlPlaceholder: 'https://searxng.example.com', + apiKeyPlaceholder: 'Nhập API key', + toasts: { + providerCreated: 'Đã tạo nhà cung cấp tìm kiếm', + providerUpdated: 'Đã cập nhật nhà cung cấp tìm kiếm', + providerDeleted: 'Đã xóa nhà cung cấp tìm kiếm', + testSuccess: 'Kết nối thành công', + testFailed: 'Kết nối thất bại' + } + }, + vectorStoreSettings: { + title: 'Engine cơ sở dữ liệu vector', + description: 'Đăng ký và quản lý các phiên bản cơ sở dữ liệu vector để tìm kiếm trong kho tri thức.', + basicSection: 'Cơ bản', + storesTitle: 'Cơ sở dữ liệu vector', + addStore: 'Thêm cơ sở dữ liệu', + editStore: 'Sửa cơ sở dữ liệu', + deleteConfirm: 'Bạn có chắc chắn muốn xóa cơ sở dữ liệu vector này?', + emptyDesc: 'Chưa có cơ sở dữ liệu vector nào. Nhấn "Thêm cơ sở dữ liệu" để bắt đầu.', + engineTypeLabel: 'Loại engine', + nameLabel: 'Tên', + namePlaceholder: 'Vd: my-vector-store', + connectionInfo: 'Thông tin kết nối', + advancedIndexConfig: 'Cài đặt nâng cao', + envTag: 'MẶC ĐỊNH', + testConnection: 'Kiểm tra kết nối', + testing: 'Đang kiểm tra...', + immutableNotice: 'Không thể thay đổi loại engine, kết nối và cấu hình chỉ mục sau khi tạo.\nĐể thay đổi, vui lòng xóa và tạo lại.', + insecureSkipVerifyWarning: 'Tắt xác thực chứng chỉ TLS có nguy cơ bị tấn công man-in-the-middle. Chỉ dùng cho cụm phát triển tự ký — không dùng trên production.', + validation: { + nameRequired: 'Vui lòng nhập tên', + engineTypeRequired: 'Vui lòng chọn loại engine', + fieldRequired: 'Vui lòng nhập {field}', + indexNamePattern: 'Phải bắt đầu bằng chữ cái. Chỉ chấp nhận chữ cái, số, gạch dưới và gạch ngang (tối đa 128 ký tự)' + }, + toasts: { + storeCreated: 'Đã tạo cơ sở dữ liệu vector', + storeUpdated: 'Đã cập nhật cơ sở dữ liệu vector', + storeDeleted: 'Đã xóa cơ sở dữ liệu vector', + testSuccess: 'Kết nối thành công', + testFailed: 'Kết nối thất bại', + duplicateName: 'Tên cơ sở dữ liệu vector này đã tồn tại', + errorGeneric: 'Đã xảy ra lỗi. Vui lòng thử lại.' + } + }, + memorySettings: { + title: 'Ký ức của tôi', + description: 'Những gì trợ lý ghi nhớ về bạn qua các cuộc trò chuyện. Bạn có thể xem, sửa hoặc xóa tại đây; ký ức đã xóa sẽ không bao giờ được dùng lại.', + workspaceDisabled: 'Ký ức dài hạn đang tắt trong không gian làm việc này. Cài đặt sẽ có hiệu lực khi quản trị viên bật lại.', + enableLabel: 'Bật ký ức dài hạn cho tôi', + enableDescription: 'Khi tắt, trợ lý sẽ không đọc hoặc ghi thêm ký ức của bạn. Ký ức hiện có vẫn được giữ nguyên và sẽ kích hoạt lại khi bạn bật.', + agentDisabledHint: 'Từng agent cũng có thể tắt ký ức dài hạn riêng. Khi trò chuyện với agent đó, ký ức sẽ không được đọc hay ghi thêm; các agent khác không bị ảnh hưởng.', + usage: { + title: 'Thời điểm sử dụng ký ức', + iconHint: 'Xem những ký ức được dùng trong hội thoại', + intro: 'Chỉ các ký ức Đang hoạt động mới được sử dụng trong hội thoại.', + rows: { + alwaysOn: { + label: 'Mọi lượt hội thoại', + text: 'Hồ sơ, tùy chọn và bất kỳ điều gì bạn yêu cầu ghi nhớ' + }, + situational: { + label: 'Khi liên quan', + text: 'Dữ kiện thực tế và các tác vụ đang thực hiện' + }, + interest: { + label: 'Chủ đề quen thuộc', + text: 'Mối quan tâm dài hạn; không nhất thiết phải đưa vào mọi câu trả lời' + }, + tracking: { + label: 'Đang theo dõi', + text: 'Chủ đề lặp lại sẽ được theo dõi trước và chỉ trở thành mối quan tâm dài hạn khi đạt ngưỡng quy định' + }, + documents: { + label: 'Nguồn quen thuộc', + text: 'Tài liệu thường xuyên được trích dẫn; truy xuất sẽ ưu tiên nhẹ các nguồn này' + }, + pending: { + label: 'Sau khi xác nhận', + text: 'Nội dung suy luận đang chờ bạn duyệt' + }, + inactive: { + label: 'Không dùng', + text: 'Các mục đã thay thế hoặc đã lưu trữ' + } + } + }, + listTitle: 'Ký ức', + listCount: 'Tổng cộng {count}', + statusActive: 'Đang hoạt động', + statusSuperseded: 'Đã thay thế', + statusArchived: 'Đã lưu trữ', + statusPending: 'Chờ duyệt', + statusTracking: 'Đang theo dõi', + statusDocuments: 'Nguồn quen thuộc', + confirmGuess: 'Đúng', + rejectGuess: 'Không', + pendingHint: 'Thông tin được suy luận từ câu hỏi của bạn. Ký ức sẽ không được dùng cho đến khi bạn xác nhận.', + trackingHint: 'Các chủ đề bạn thường hỏi nhưng chưa đạt ngưỡng để thành mối quan tâm dài hạn. Chưa được dùng trong hội thoại.', + documentsHint: 'Tài liệu liên tục xuất hiện trong câu trả lời nên được ưu tiên truy xuất hơn. Dừng theo dõi để hủy ưu tiên; tài liệu sẽ xuất hiện lại sau 2 lần trích dẫn tiếp theo.', + supersededHint: 'Đã được thay thế bằng ký ức mới hơn. Được giữ lại làm lịch sử thay đổi và không dùng trong hội thoại.', + archivedHint: 'Ký ức lưu trữ không được dùng trong hội thoại. Khi đạt giới hạn cá nhân, các mục ít dùng sẽ được tự động cất đi.', + pendingEmptyTitle: 'Không có mục nào cần duyệt', + pendingEmptyDescription: 'Khi có thông tin được suy luận từ câu hỏi của bạn, nội dung sẽ chờ bạn xác nhận tại đây.', + trackingEmptyTitle: 'Chưa có chủ đề nào đang theo dõi', + trackingEmptyDescription: 'Khi bật tự động đúc kết, hệ thống sẽ ghi nhận chủ đề bạn thường hỏi và chuyển thành mối quan tâm dài hạn khi lặp lại đủ số lần.', + documentsEmptyTitle: 'Chưa có nguồn quen thuộc nào', + documentsEmptyDescription: 'Tài liệu sẽ xuất hiện tại đây sau khi được trích dẫn trong câu trả lời ít nhất 2 lần.', + supersededEmptyTitle: 'Chưa có mục nào bị thay thế', + supersededEmptyDescription: 'Khi có thông tin mới thay thế nội dung cũ, bản cũ sẽ nằm ở đây. Chỉnh sửa trực tiếp tại trang này sẽ cập nhật ngay mà không tạo lịch sử.', + archivedEmptyTitle: 'Chưa có mục nào được lưu trữ', + archivedEmptyDescription: 'Khi ký ức hoạt động vượt giới hạn (mặc định 200), các mục ít dùng sẽ tự động lưu trữ. Các tác vụ có thời hạn cũng sẽ chuyển về đây khi hết hạn.', + documentsHits: 'Đã trích dẫn {hits} lần', + untitledDocument: 'Tài liệu chưa đặt tên', + openDocument: 'Mở tài liệu', + openDocumentUnavailable: 'Không thể mở: thiếu kho tri thức', + stopTrackingDocument: 'Ngừng theo dõi', + stopTrackingDocumentConfirm: 'Ngừng dùng tài liệu này để truy xuất cá nhân hóa? Tài liệu sẽ xuất hiện lại sau hai lần trích dẫn nữa.', + stopTrackingDocumentSuccess: 'Đã ngừng theo dõi nguồn này', + stopTrackingDocumentFailed: 'Ngừng theo dõi thất bại', + trackingProgress: 'Đã hỏi {hits} lần; sẽ trở thành mối quan tâm dài hạn khi đạt {threshold}', + trackingReady: 'Đã đạt ngưỡng — bạn có thể lưu thành mối quan tâm dài hạn', + trackingAliases: 'Tên gọi khác: {aliases}', + promoteTopic: 'Lưu thành mối quan tâm', + dismissTopic: 'Bỏ theo dõi', + dismissTopicConfirm: 'Bỏ theo dõi chủ đề này? Các câu hỏi tiếp theo sẽ không tự động lưu chủ đề thành mối quan tâm dài hạn.', + promoteSuccess: 'Đã lưu thành mối quan tâm dài hạn', + promoteFailed: 'Lưu thành mối quan tâm thất bại', + dismissSuccess: 'Đã bỏ theo dõi chủ đề này', + dismissFailed: 'Bỏ theo dõi thất bại', + confirmSuccess: 'Đã xác nhận', + confirmFailed: 'Xác nhận thất bại', + rejectSuccess: 'Đã từ chối. Sẽ không tự động suy luận lại.', + rejectFailed: 'Từ chối thất bại', + export: 'Xuất dữ liệu', + consolidate: 'Dọn dẹp', + consolidateConfirm: 'Các mục gần giống nhau sẽ được hợp nhất. Nội dung cũ sẽ nằm trong mục Đã thay thế. Tiếp tục?', + consolidateSuccess: 'Đã dọn dẹp: hợp nhất {merged} nhóm, lưu trữ {expired} mục hết hạn, hạ cấp {demoted} tác vụ cũ', + consolidateNothing: 'Không có nội dung cần dọn dẹp', + consolidateTooFewItems: 'Chưa đủ dữ liệu bộ nhớ để dọn dẹp', + consolidateNoCandidates: 'Không tìm thấy bộ nhớ tương đồng để hợp nhất', + consolidateModelDeclined: 'Mô hình xác định đây là các nội dung khác nhau nên không hợp nhất', + consolidateTooSoon: 'Vừa thực hiện dọn dẹp. Vui lòng thử lại sau giây lát.', + consolidateModelUnavailable: 'Mô hình hiện không khả dụng, giữ nguyên để tránh hợp nhất sai', + consolidateFailed: 'Dọn dẹp thất bại', + clear: 'Xóa tất cả', + clearConfirm: 'Thao tác này sẽ xóa vĩnh viễn toàn bộ bộ nhớ, chủ đề đang theo dõi và các nguồn quen thuộc, không thể hoàn tác. Tiếp tục?', + deleteConfirm: 'Xóa vĩnh viễn bộ nhớ này?', + add: 'Thêm', + addPlaceholder: 'Nhập một câu bạn muốn trợ lý ghi nhớ', + addTitle: 'Thêm bộ nhớ', + addKindLabel: 'Loại', + addContentLabel: 'Nội dung', + emptyTitle: 'Chưa có bộ nhớ nào', + emptyDescription: 'Nhập "hãy nhớ rằng..." trong hội thoại, hoặc thêm trực tiếp ở trên.', + kinds: { + profile: 'Thông tin cá nhân', + preference: 'Sở thích', + fact: 'Dữ kiện', + task: 'Tác vụ đang xử lý', + interest: 'Mối quan tâm dài hạn' + }, + kindHints: { + profile: 'Áp dụng cho mọi lượt trò chuyện sau này', + preference: 'Áp dụng cho mọi lượt trò chuyện sau này', + fact: 'Chỉ dùng khi câu hỏi có liên quan', + task: 'Chỉ dùng khi câu hỏi có liên quan', + interest: 'Giúp trợ lý hiểu chủ đề bạn thường hỏi; không nhất thiết trích dẫn ở mọi lượt' + }, + origins: { + explicit: 'Bạn yêu cầu', + extracted: 'Tự động trích xuất', + manual: 'Thêm thủ công' + }, + toasts: { + enabled: 'Đã bật bộ nhớ dài hạn', + disabled: 'Đã tắt bộ nhớ dài hạn', + added: 'Đã thêm', + updated: 'Đã cập nhật', + deleted: 'Đã xóa', + cleared: 'Đã xóa {count} bộ nhớ', + saveFailed: 'Thao tác thất bại: {message}' + } + }, + envVarSettings: { + title: 'Bí mật Sandbox', + description: 'Khóa bí mật cá nhân cho kỹ năng và Sandbox, không phải cấu hình hệ thống hay triển khai WeKnora.', + helpAria: 'Tìm hiểu về bí mật Sandbox', + introPersonalTitle: 'Chỉ riêng bạn', + introPersonalBody: 'Được nạp vào đoạn chat và tác vụ của riêng bạn. Thành viên khác không thể xem và khóa của họ không ghi đè khóa của bạn.', + introRuntimeTitle: 'Nạp khi khởi chạy', + introRuntimeBody: 'Được nạp khi kỹ năng chạy hoặc khi lệnh thực thi trong Sandbox đó. Bạn cũng có thể cung cấp ngay trong hội thoại. Giá trị đã lưu sẽ không hiển thị lại.', + loading: 'Đang tải…', + loadFailed: 'Không thể tải bí mật Sandbox.', + retry: 'Thử lại', + noConfigTitle: 'Chưa cấu hình Sandbox', + noConfigDescription: 'Không gian làm việc này chưa có môi trường Sandbox nên chưa thể thiết lập khóa.', + sandboxTitle: 'Luôn nạp vào Sandbox đã chọn', + sandboxHint: 'Chỉ nạp cho các lệnh bạn chạy trong Sandbox đó. Hầu như không cần thiết lập; bạn cũng có thể nhập trực tiếp trong hội thoại.', + sandboxEmpty: 'Chưa có mục nào.', + sandboxPick: 'Chọn Sandbox', + skillTitle: 'Khóa kỹ năng yêu cầu', + skillHint: 'Mỗi kỹ năng sẽ khai báo các khóa cần thiết. Lưu trước tại đây hoặc nhập khi trò chuyện. Quản trị viên không gian làm việc cũng có thể cấu hình giá trị dùng chung trên thẻ kỹ năng.', + skillEmptyTitle: 'Chưa có kỹ năng nào yêu cầu khóa', + skillEmptyDesc: 'Khi bạn cài đặt kỹ năng yêu cầu thông tin xác thực, các trường cần điền sẽ xuất hiện tại đây.', + skillOnSandbox: 'Sandbox: {name}', + skillNeedsCount: 'Chưa lưu {count} khóa tại đây', + skillReady: 'Đã lưu trên trang này', + requiredTag: 'Bắt buộc', + statusUnset: 'Chưa thiết lập', + statusWorkspace: 'Dùng giá trị của không gian làm việc', + statusUser: 'Bạn đã thiết lập', + setValue: 'Thiết lập', + replaceValue: 'Thay thế', + addRow: 'Thêm', + namePlaceholder: 'TEN_BIEN', + nameRule: 'Chữ in hoa, số và dấu gạch dưới; bắt đầu bằng chữ cái hoặc dấu gạch dưới.', + nameInvalid: 'Không thể sử dụng tên này. Hệ thống không chấp nhận các tên Sandbox dành riêng như PATH hoặc bắt đầu bằng WEKNORA_.', + nameDuplicate: 'Biến với tên này đã tồn tại tại đây.', + valuePlaceholder: 'Nhập giá trị', + storedPlaceholder: 'Đã lưu, nhập để thay thế', + valueRequired: 'Vui lòng nhập giá trị trước khi lưu.', + valueTooLong: 'Giá trị không được vượt quá {max} byte.', + tooManyValues: 'Bạn chỉ có thể lưu tối đa {max} biến tại đây.', + save: 'Lưu', + saveSuccess: 'Đã lưu. Giá trị đã được lưu trữ và sẽ không hiển thị lại.', + saveFailed: 'Không thể lưu giá trị.', + delete: 'Xóa', + deleteConfirm: 'Xóa {name}? Biến này sẽ không còn được truyền vào bất kỳ tác vụ nào chạy trên Sandbox này.', + deleteSuccess: 'Đã xóa biến.', + clear: 'Xóa giá trị của tôi', + clearConfirm: 'Xóa giá trị riêng của bạn cho {name}? Giá trị của không gian làm việc (nếu có) sẽ được áp dụng trở lại sau đó.', + clearSuccess: 'Đã xóa giá trị của bạn.', + updatedAt: 'Bạn đã thiết lập vào {time}', + host: { + title: 'Biến môi trường', + description: 'Khóa cá nhân cho các kỹ năng trên máy chủ này, không phải cài đặt hệ thống hoặc triển khai WeKnora.', + helpAria: 'Thông tin về biến môi trường', + introRuntimeBody: 'Được chèn khi kỹ năng chạy trên máy chủ này. Bạn cũng có thể cung cấp giá trị trong đoạn chat. Giá trị đã lưu sẽ không hiển thị lại.', + loadFailed: 'Không thể tải danh sách biến môi trường.', + sandboxTitle: 'Luôn bao gồm trên máy chủ này', + sandboxHint: 'Chỉ gửi cùng các lệnh chạy trên máy chủ này. Để trống nếu bạn không cần. Bạn cũng có thể cung cấp giá trị trong đoạn chat.', + nameInvalid: 'Không thể sử dụng tên này. Các tên dành riêng (ví dụ: PATH hoặc bắt đầu bằng WEKNORA_) sẽ bị từ chối.', + deleteConfirm: 'Xóa {name}? Các lần chạy sau trên máy chủ này sẽ không còn bao gồm biến này.' + } + }, + auth: { + workspaceOnboarding: { + inviteOnlyDescription: 'Tính năng tự tạo không gian làm việc đã bị tắt. Vui lòng xem và chấp nhận lời mời từ quản trị viên.', + inviteOnlyNotice: 'Tài khoản này chỉ có thể tham gia không gian làm việc hiện có qua lời mời', + help: 'Bạn có thể tạo không gian làm việc ngay bây giờ hoặc quay lại sau để chấp nhận lời mời.', + inviteOnlyHelp: 'Chưa nhận được lời mời? Hãy gửi địa chỉ email đăng ký cho quản trị viên để được mời.', + title: 'Chọn không gian làm việc', + description: 'Tạo không gian làm việc mới để bắt đầu, hoặc chấp nhận lời mời tham gia không gian hiện có.', + create: 'Tạo không gian làm việc', + invitations: 'Xem lời mời', + loadingPolicy: 'Đang kiểm tra các tùy chọn không gian làm việc khả dụng…', + policyLoadFailed: 'Không thể tải quyền không gian làm việc. Kiểm tra kết nối và thử lại.', + retry: 'Tải lại', + inviteOnlyTitle: 'Đang chờ lời mời vào không gian làm việc' + }, + login: 'Đăng nhập', + logout: 'Đăng xuất', + oidcLogin: 'Đăng nhập bằng OIDC', + oidcLoginWithProvider: 'Đăng nhập bằng {provider}', + redirectingToOIDC: 'Đang chuyển hướng đến nhà cung cấp danh tính...', + orContinueWith: 'Hoặc tiếp tục với', + oidcLoginFailed: 'Đăng nhập OIDC thất bại', + username: 'Tên người dùng', + email: 'Email', + password: 'Mật khẩu', + confirmPassword: 'Xác nhận mật khẩu', + loginSuccessTitle: 'Đăng nhập thành công', + loginSuccessContent: 'Chào mừng trở lại. Bạn hiện đang ở {name}', + loggingIn: 'Đang đăng nhập...', + register: 'Đăng ký', + registering: 'Đang đăng ký...', + createAccount: 'Tạo tài khoản', + haveAccount: 'Đã có tài khoản?', + backToLogin: 'Quay lại đăng nhập', + loginHint: 'Đăng nhập để tiếp tục, hoặc tạo tài khoản bên dưới nếu bạn mới truy cập lần đầu.', + firstTime: 'Lần đầu dùng WeKnora?', + registerSuccess: 'Đăng ký thành công. Vui lòng đăng nhập', + registerFailed: 'Đăng ký thất bại', + subtitle: 'Hỏi đáp RAG, ReAct Agent và Wiki — nền tảng quản trị tri thức doanh nghiệp vận hành bởi LLM', + registerSubtitle: 'Tạo tài khoản để bắt đầu sử dụng WeKnora', + emailPlaceholder: 'Nhập địa chỉ email', + passwordPlaceholder: 'Nhập mật khẩu', + confirmPasswordPlaceholder: 'Nhập lại mật khẩu', + usernamePlaceholder: 'Nhập tên người dùng', + emailRequired: 'Vui lòng nhập địa chỉ email', + emailInvalid: 'Định dạng email không hợp lệ', + passwordRequired: 'Vui lòng nhập mật khẩu', + passwordMinLength: 'Mật khẩu phải có ít nhất 8 ký tự', + passwordMaxLength: 'Mật khẩu không được vượt quá 32 ký tự', + passwordMustContainLetter: 'Mật khẩu phải chứa chữ cái', + passwordMustContainLowercaseLetter: 'Mật khẩu phải chứa chữ thường', + passwordMustContainUppercaseLetter: 'Mật khẩu phải chứa chữ hoa', + passwordMustContainNumber: 'Mật khẩu phải chứa chữ số', + passwordMustContainSpecialChar: 'Mật khẩu phải chứa ký tự đặc biệt: {specialChars}', + usernameRequired: 'Vui lòng nhập tên người dùng', + usernameMinLength: 'Tên người dùng phải có ít nhất 2 ký tự', + usernameMaxLength: 'Tên người dùng không được vượt quá 20 ký tự', + usernameInvalid: 'Tên người dùng chỉ được chứa chữ cái, chữ số, dấu gạch dưới và chữ Hán', + confirmPasswordRequired: 'Vui lòng xác nhận mật khẩu', + passwordMismatch: 'Mật khẩu đã nhập không khớp', + loginError: 'Lỗi đăng nhập, vui lòng kiểm tra email hoặc mật khẩu', + loginErrorRetry: 'Lỗi đăng nhập, vui lòng thử lại sau', + registerError: 'Lỗi đăng ký, vui lòng thử lại sau' + }, + authStore: { + errors: { + parseUserFailed: 'Không thể phân tích dữ liệu người dùng', + parseTenantFailed: 'Không thể phân tích dữ liệu không gian làm việc', + parseKnowledgeBasesFailed: 'Không thể phân tích danh sách kho tri thức', + parseCurrentKnowledgeBaseFailed: 'Không thể phân tích kho tri thức hiện tại' + } + }, + common: { + add: 'Thêm', + me: 'Tôi', + confirm: 'Xác nhận', + cancel: 'Hủy', + unsavedChanges: { + title: 'Thay đổi chưa lưu', + body: 'Các thay đổi sẽ bị mất nếu bạn đóng lúc này. Vẫn muốn đóng?', + discard: 'Bỏ thay đổi', + keepEditing: 'Tiếp tục chỉnh sửa' + }, + fullscreen: 'Toàn màn hình', + exitFullscreen: 'Thoát toàn màn hình', + save: 'Lưu', + delete: 'Xóa', + edit: 'Chỉnh sửa', + copy: 'Sao chép', + copied: 'Đã sao chép', + copySuccess: 'Sao chép thành công', + default: 'Mặc định', + create: 'Tạo', + download: 'Tải xuống', + refresh: 'Làm mới', + loading: 'Đang tải...', + noData: 'Không có dữ liệu', + noMoreData: 'Đã tải hết nội dung', + loadMore: 'Tải thêm', + error: 'Lỗi', + success: 'Thành công', + failed: 'Thất bại', + info: 'Thông tin', + selectAll: 'Chọn tất cả', + yes: 'Có', + no: 'Không', + close: 'Đóng', + back: 'Quay lại', + next: 'Tiếp tục', + finish: 'Hoàn tất', + all: 'Tất cả', + clear: 'Xóa', + website: 'Trang web chính thức', + clawhubSkill: 'Kỹ năng Claw', + github: 'GitHub', + githubStarTip: 'Xem repo trên GitHub — tặng sao nếu thấy hữu ích', + on: 'Bật', + off: 'Tắt', + confirmDelete: 'Xác nhận xóa', + createSuccess: 'Tạo thành công', + deleteSuccess: 'Xóa thành công', + deleteFailed: 'Xóa thất bại', + updateSuccess: 'Cập nhật thành công', + saveSuccess: 'Lưu thành công', + saveFailed: 'Lưu thất bại', + operationFailed: 'Thao tác thất bại', + file: 'Tệp', + skill: 'Kỹ năng', + knowledgeBase: 'Kho tri thức', + noResult: 'Không tìm thấy kết quả', + remove: 'Gỡ bỏ', + avatar: 'Ảnh đại diện', + defaultUser: 'Người dùng', + copyFailed: 'Sao chép thất bại', + retry: 'Thử lại', + expand: 'Mở rộng', + collapse: 'Thu gọn' + }, + mentionDetail: { + readOnlyFromAgent: 'Chỉ đọc trong cuộc trò chuyện này; không hiển thị trong danh sách Kho tri thức', + faqCount: '{count} mục hỏi-đáp', + kbCount: '{count} tài liệu', + mcpToolCount: '{count} công cụ', + mcpNotSynced: 'Công cụ chưa được đồng bộ', + mcpStale: 'Cần đồng bộ lại', + belongsToKb: 'Kho tri thức: ', + belongsToOrg: 'Không gian: ', + noCompatibleKbForAgent: 'Công cụ của agent này không khớp với năng lực của kho tri thức nào trong phạm vi, không thể tham chiếu.' + }, + file: { + upload: 'Tải tệp lên' + }, + manualEditor: { + placeholders: { + heading: 'Tiêu đề {level}', + listItem: 'Mục danh sách', + taskItem: 'Mục công việc', + quote: 'Nội dung trích dẫn', + code: 'Nội dung mã', + linkText: 'Văn bản liên kết', + imageAlt: 'Mô tả ảnh', + bold: 'Chữ đậm', + italic: 'Chữ nghiêng', + strike: 'Gạch ngang', + inlineCode: 'mã nội dòng' + }, + table: { + column1: 'Cột 1', + column2: 'Cột 2', + cell: 'Nội dung' + }, + toolbar: { + bold: 'Đậm', + italic: 'Nghiêng', + strike: 'Gạch ngang', + inlineCode: 'Mã nội dòng', + heading1: 'Tiêu đề 1', + heading2: 'Tiêu đề 2', + heading3: 'Tiêu đề 3', + bulletList: 'Danh sách dấu đầu dòng', + orderedList: 'Danh sách đánh số', + taskList: 'Danh sách công việc', + blockquote: 'Trích dẫn', + codeBlock: 'Khối mã', + link: 'Chèn liên kết', + image: 'Chèn hình ảnh', + table: 'Chèn bảng', + horizontalRule: 'Đường phân cách', + headingGroup: 'Tiêu đề', + insertGroup: 'Chèn' + }, + shortcuts: { + title: 'Phím tắt', + continueList: 'Tiếp tục danh sách', + indent: 'Thụt lề / Shift+Tab để lùi lề' + }, + view: { + edit: 'Chỉnh sửa', + split: 'Chia đôi', + preview: 'Xem trước', + splitUnavailable: 'Mở rộng ngăn kéo hoặc bật toàn màn hình để chia đôi chế độ xem', + groupLabel: 'Chế độ xem' + }, + preview: { + empty: 'Chưa có nội dung' + }, + title: { + edit: 'Chỉnh sửa tri thức Markdown', + create: 'Tạo tri thức Markdown' + }, + section: { + content: 'Nội dung' + }, + labels: { + currentKnowledgeBase: 'Kho tri thức hiện tại' + }, + defaultTitlePrefix: 'Tài liệu mới', + error: { + fetchDetailFailed: 'Không thể tải chi tiết tri thức', + saveFailed: 'Lưu thất bại, vui lòng thử lại sau' + }, + warning: { + selectKnowledgeBase: 'Vui lòng chọn kho tri thức đích', + enterTitle: 'Vui lòng nhập tiêu đề tri thức', + enterContent: 'Vui lòng nhập nội dung tri thức', + contentTooShort: 'Nội dung quá ngắn. Vui lòng bổ sung thêm thông tin trước khi xuất bản' + }, + success: { + draftSaved: 'Đã lưu bản nháp', + published: 'Đã xuất bản tri thức và bắt đầu lập chỉ mục' + }, + form: { + knowledgeBasePlaceholder: 'Chọn kho tri thức', + titleLabel: 'Tiêu đề tri thức', + knowledgeBaseLabel: 'Kho tri thức đích', + titlePlaceholder: 'Nhập tiêu đề', + contentPlaceholder: 'Hỗ trợ Markdown. Dùng # cho tiêu đề, danh sách, khối mã, v.v.' + }, + noDocumentKnowledgeBases: 'Không có kho tri thức dạng tài liệu. Vui lòng tạo trước', + status: { + draftTag: 'Trạng thái: Bản nháp', + publishedTag: 'Trạng thái: Đã xuất bản', + lastUpdated: 'Cập nhật lần cuối: {time}', + counter: '{chars} ký tự · {lines} dòng' + }, + loading: { + content: 'Đang tải nội dung...', + preparing: 'Đang chuẩn bị trình soạn thảo...' + }, + actions: { + cancel: 'Hủy', + saveDraft: 'Lưu nháp', + publish: 'Xuất bản' + } + }, + graphSettings: { + startExtraction: 'Bắt đầu trích xuất', + extracting: 'Đang trích xuất...', + defaultExample: 'Ví dụ mặc định', + clearExample: 'Xóa ví dụ', + completeModelConfig: 'Vui lòng hoàn tất cấu hình mô hình trước', + tagsGenerated: 'Tạo thẻ thành công', + tagsGenerateFailed: 'Tạo thẻ thất bại', + textGenerated: 'Tạo văn bản thành công', + textGenerateFailed: 'Tạo văn bản thất bại', + pleaseInputText: 'Vui lòng nhập văn bản mẫu trước', + extractSuccess: 'Trích xuất thực thể - quan hệ thành công', + extractFailed: 'Trích xuất thực thể - quan hệ thất bại', + exampleLoaded: 'Đã tải ví dụ', + exampleCleared: 'Đã xóa ví dụ', + disabledWarning: 'Cơ sở dữ liệu đồ thị tri thức chưa được bật, không thể trích xuất thực thể - quan hệ', + howToEnable: 'Cách bật đồ thị tri thức?', + title: 'Cấu hình đồ thị tri thức', + description: 'Cấu hình trích xuất thực thể - quan hệ để tự động tạo đồ thị tri thức từ văn bản (lưu ý: khác với "đồ thị liên kết trang" trong Wiki — đồ thị đó hiển thị liên kết tham chiếu giữa các trang Wiki, còn đây là đồ thị thực thể - quan hệ do LLM trích xuất)', + enableLabel: 'Bật trích xuất thực thể - quan hệ', + enableDescription: 'Tự động trích xuất thực thể và mối quan hệ từ văn bản khi bật', + tagsLabel: 'Loại quan hệ', + tagsDescription: 'Xác định các thẻ loại quan hệ cần trích xuất, phân tách bằng dấu phẩy', + tagsPlaceholder: 'Nhập loại quan hệ, ví dụ: works_at, colleague, friend', + generateRandomTags: 'Tạo thẻ ngẫu nhiên', + sampleTextLabel: 'Văn bản mẫu', + sampleTextDescription: 'Văn bản mẫu để kiểm tra trích xuất thực thể - quan hệ', + sampleTextPlaceholder: 'Nhập văn bản chứa thực thể và mối quan hệ...', + customInstructionsLabel: 'Chỉ dẫn trích xuất bổ sung', + customInstructionsDescription: 'Thêm phạm vi chuyên môn, lọc thực thể hoặc hướng dẫn thuộc tính trong khi hệ thống vẫn duy trì chuẩn đầu ra có cấu trúc', + customInstructionsPlaceholder: 'Ví dụ: tập trung vào các bên trong hợp đồng, số tiền, ngày thực hiện và nghĩa vụ pháp lý…', + generateRandomText: 'Tạo văn bản ngẫu nhiên', + entityListLabel: 'Danh sách thực thể', + entityListDescription: 'Các thực thể và thuộc tính được trích xuất từ văn bản', + nodeNamePlaceholder: 'Nhập tên thực thể', + attributePlaceholder: 'Nhập giá trị thuộc tính', + addAttribute: 'Thêm thuộc tính', + manageEntitiesLabel: 'Quản lý thực thể', + manageEntitiesDescription: 'Thêm hoặc xóa các nút thực thể', + addEntity: 'Thêm thực thể', + relationListLabel: 'Danh sách quan hệ', + relationListDescription: 'Xác định liên kết quan hệ giữa các thực thể', + selectEntity: 'Chọn thực thể', + selectRelationType: 'Chọn loại quan hệ', + manageRelationsLabel: 'Quản lý quan hệ', + manageRelationsDescription: 'Thêm hoặc xóa mối quan hệ giữa các thực thể', + addRelation: 'Thêm quan hệ', + extractActionsLabel: 'Thao tác trích xuất', + extractActionsDescription: 'Thực hiện trích xuất thực thể - quan hệ hoặc quản lý dữ liệu mẫu' + }, + initialization: { + skip: 'Bỏ qua', + next: 'Tiếp tục' + }, + inviteRegister: { + bannerTitle: 'Bạn được mời tham gia "{tenant}"', + bannerHint: 'Điền thông tin bên dưới để đăng ký. Bạn sẽ tự động tham gia nhóm sau khi hoàn tất.', + bannerHintLogin: 'Đăng nhập để tự động tham gia nhóm này.', + loading: 'Đang xác thực liên kết mời…', + invalidTitle: 'Liên kết mời không hợp lệ hoặc đã bị thu hồi', + invalidBody: 'Yêu cầu người mời gửi liên kết mới hoặc đăng nhập bằng tài khoản hiện có.', + backToLogin: 'Quay lại đăng nhập', + title: 'Hoàn tất đăng ký', + subtitle: 'Bạn được mời tham gia “{tenant}”', + email: 'Email', + emailPlaceholder: 'your{\'@\'}example.com', + emailHint: 'Sử dụng bất kỳ email nào bạn sở hữu.', + emailInvalid: 'Vui lòng nhập địa chỉ email hợp lệ', + username: 'Tên hiển thị', + usernamePlaceholder: 'Nhập tên hiển thị', + password: 'Đặt mật khẩu', + passwordPlaceholder: 'Tối thiểu 6 ký tự', + confirmPassword: 'Xác nhận mật khẩu', + submit: 'Hoàn tất đăng ký', + submitting: 'Đang gửi…', + success: 'Đăng ký thành công — đang chuyển đến không gian làm việc…', + joined: 'Bạn đã tham gia nhóm.', + failed: 'Đăng ký thất bại; vui lòng thử lại sau', + usernameRequired: 'Vui lòng nhập tên hiển thị', + passwordTooShort: 'Mật khẩu phải có ít nhất 6 ký tự', + passwordMismatch: 'Mật khẩu không khớp' + }, + memoryWorkspaceSettings: { + title: 'Bộ nhớ dài hạn', + description: 'Cho phép trợ lý ghi nhớ thông tin thành viên chia sẻ — danh tính, thói quen làm việc, dữ kiện cố định và công việc đang xử lý — xuyên suốt các cuộc trò chuyện.', + introTitle: 'Mặc định tắt, cần chủ động bật', + introDescription: 'Bộ nhớ dài hạn lưu giữ những gì thành viên nói trong cuộc trò chuyện, vì vậy tính năng này mặc định không được bật. Khi kích hoạt, mỗi thành viên có một không gian bộ nhớ tách biệt và có thể xem, chỉnh sửa, xóa hoặc tắt hoàn toàn tại mục "Bộ nhớ của tôi". Thông tin hồ sơ và tùy chọn đang hoạt động sẽ được đưa vào mọi lượt tương tác sau; các dữ kiện và tác vụ đang diễn ra chỉ được nhớ lại khi câu hỏi có liên quan.', + enableLabel: 'Bật bộ nhớ dài hạn trong không gian làm việc này', + enableDescription: 'Khi tắt, không cuộc trò chuyện nào trong không gian làm việc này có thể đọc hoặc ghi bộ nhớ.', + writeModeLabel: 'Cơ chế ghi nhớ', + writeModeDescription: 'Kiểm soát những nội dung được ghi nhớ.', + writeModeExplicit: 'Chỉ khi yêu cầu', + writeModeAuto: 'Tự động chắt lọc', + writeModeExplicitHint: 'Chỉ ghi nhớ những gì thành viên yêu cầu rõ ràng, cùng các mục được thêm thủ công. Không gọi thêm mô hình.', + writeModeAutoHint: 'Gọi thêm một mô hình chạy ngầm sau cuộc trò chuyện để chắt lọc những nội dung đáng lưu giữ từ chia sẻ của thành viên.', + extractModelLabel: 'Mô hình chắt lọc', + extractModelDescription: 'Để trống để dùng chính mô hình mà cuộc trò chuyện đang sử dụng.', + extractDelayLabel: 'Độ trễ chắt lọc', + extractDelayDescription: 'Thời gian chờ sau khi lượt tương tác kết thúc trước khi chạy chắt lọc. Việc chờ giúp một lần gọi mô hình có thể bao quát nhiều tin nhắn người dùng gửi liên tiếp.', + extractMinIntervalLabel: 'Khoảng thời gian tối thiểu giữa các lần chạy', + extractMinIntervalDescription: 'Khoảng cách tối thiểu giữa hai lần chắt lọc cho một người dùng nhằm kiểm soát chi phí. Các tin nhắn phát sinh trong khoảng này không bị bỏ qua — chúng sẽ được chuyển sang lần chạy tiếp theo.', + vectorRecallLabel: 'Đối sánh bộ nhớ theo ngữ nghĩa', + vectorRecallDescription: 'Bổ sung đối sánh ngữ nghĩa bên cạnh khớp từ ngữ, giúp bộ nhớ vẫn hiển thị khi người dùng diễn đạt lại vấn đề. Tốn một lượt gọi embedding cho mỗi lượt tương tác, và tự động chuyển về chỉ khớp từ ngữ nếu quá thời gian chờ.', + embeddingModelLabel: 'Mô hình embedding bộ nhớ', + embeddingModelDescription: 'Truy xuất ngữ nghĩa sử dụng duy nhất mô hình này, độc lập với mô hình embedding gắn trong kho tri thức. Để trống để chỉ khớp từ ngữ. Sau khi đổi, các bộ nhớ mới sẽ dùng mô hình mới ngay; bộ nhớ hiện có vẫn chỉ khớp từ ngữ cho đến khi được Embedding lại.', + conditioningLabel: 'Dùng bộ nhớ để định hình truy xuất', + conditioningDescription: 'Bộ nhớ tham gia viết lại truy vấn và xếp hạng tài liệu thay vì chỉ được ghép vào prompt câu trả lời. Đây là điểm mấu chốt phát huy giá trị của bộ nhớ trong kho tri thức.', + interestThresholdLabel: 'Số câu hỏi để ghi nhận một chủ đề quan tâm', + interestThresholdDescription: 'Một chủ đề chỉ được ghi nhận sau khi được nhắc đến đủ số lần này. Đặt là 1 sẽ ghi nhận mọi câu hỏi thoáng qua, thường tạo ra nhiều dữ liệu nhiễu.', + instructionsLabel: 'Quy tắc chắt lọc tùy chỉnh', + instructionsDescription: 'Các quy tắc không gian làm việc được nối vào prompt chắt lọc, dùng cho các chính sách hệ thống không tự suy diễn được — ví dụ: "không bao giờ ghi nhớ tên khách hàng".', + instructionsPlaceholder: 'Một quy tắc mỗi dòng, ví dụ: không bao giờ ghi nhớ tên khách hàng', + maxItemsLabel: 'Số lượng ký ức mỗi thành viên', + maxItemsDescription: 'Vượt quá mốc này, các ký ức xếp hạng thấp nhất sẽ được lưu trữ dựa trên mức độ quan trọng và độ mới. Ký ức đã lưu trữ vẫn xem được tại "Bộ nhớ của tôi".', + toasts: { + saveSuccess: 'Đã lưu cài đặt bộ nhớ dài hạn', + saveFailed: 'Lưu cài đặt thất bại: {message}' + } + }, + chatHistorySettings: { + title: 'Quản lý tin nhắn', + description: 'Cấu hình kho tri thức lịch sử trò chuyện để tự động lập chỉ mục tin nhắn phục vụ tìm kiếm ngữ nghĩa', + enableLabel: 'Bật lập chỉ mục tin nhắn', + enableDescription: 'Khi bật, tin nhắn mới trong cuộc trò chuyện sẽ tự động được lập chỉ mục vào kho tri thức để tìm kiếm vector', + embeddingModelLabel: 'Mô hình Embedding', + embeddingModelDescription: 'Chọn mô hình embedding để Embedding tin nhắn trò chuyện', + embeddingModelLocked: 'Tin nhắn đã được lập chỉ mục; không thể đổi mô hình embedding (cần xóa dữ liệu đã lập chỉ mục)', + statsTitle: 'Thống kê chỉ mục', + statsIndexedMessages: 'Tin nhắn đã lập chỉ mục', + statsNotConfigured: 'Chưa cấu hình lập chỉ mục tin nhắn', + statsNotConfiguredDesc: 'Bật và chọn mô hình embedding để bắt đầu tự động lập chỉ mục tin nhắn trò chuyện', + toasts: { + saveSuccess: 'Đã lưu cấu hình quản lý tin nhắn', + saveFailed: 'Lưu cấu hình thất bại: {message}' + } + }, + retrievalSettings: { + title: 'Cài đặt tìm kiếm', + description: 'Cấu hình tham số truy xuất toàn cục cho tìm kiếm tri thức và tin nhắn', + embeddingTopKLabel: 'Top K tìm kiếm vector', + vectorThresholdLabel: 'Ngưỡng tương đồng vector', + keywordThresholdLabel: 'Ngưỡng khớp từ khóa', + rerankTopKLabel: 'Top K Rerank', + rerankThresholdLabel: 'Ngưỡng Rerank', + rerankModelLabel: 'Mô hình Rerank (Rerank)', + rerankModelDescription: 'Chọn mô hình để Rerank kết quả tìm kiếm', + rerankModelRequired: 'Vui lòng chọn mô hình Rerank. Quá trình tìm kiếm cần mô hình này để Rerank kết quả.', + toasts: { + saveSuccess: 'Đã lưu cấu hình truy xuất', + saveFailed: 'Lưu cấu hình thất bại: {message}' + } + }, + input: { + addModel: 'Thêm mô hình', + placeholder: 'Đặt câu hỏi hoặc mô tả tác vụ…', + agentMode: 'Suy luận thông minh', + normalMode: 'Trả lời nhanh', + normalModeDesc: 'Hỏi đáp RAG từ kho tri thức', + agentModeDesc: 'Tư duy nhiều bước, phân tích sâu', + agentMissingAllowedTools: 'Công cụ được phép', + agentMissingSummaryModel: 'Mô hình trò chuyện', + agentMissingRerankModel: 'Mô hình Rerank', + customAgentMissingSummaryModel: 'Mô hình trò chuyện', + customAgentMissingRerankModel: 'Mô hình Rerank', + goToAgentEditor: 'Đi tới cấu hình →', + agentNotReadyDetail: 'Agent "{agentName}" chưa sẵn sàng. Vui lòng cấu hình: {reasons}', + sharedAgentNotReadyDetail: 'Agent được chia sẻ "{agentName}" chưa sẵn sàng (thiếu: {reasons}). Hãy liên hệ quản trị viên tổ chức chia sẻ để hoàn tất thiết lập.', + webSearch: { + toggleOn: 'Bật tìm kiếm web', + toggleOff: 'Tắt tìm kiếm web', + notConfigured: 'Chưa cấu hình công cụ tìm kiếm web' + }, + knowledgeBase: 'Kho tri thức', + knowledgeBaseWithCount: 'Kho tri thức ({count})', + notConfigured: 'Chưa cấu hình', + sharedAgentModelLabel: 'Mô hình từ agent được chia sẻ', + noModel: 'Không có mô hình khả dụng', + stopGeneration: 'Dừng tạo', + send: 'Gửi', + steerCurrent: 'Bổ sung cho tác vụ hiện tại', + steerAfter: 'Gửi sau khi hoàn thành', + steerAccepted: 'Đã thêm vào tác vụ này', + steerRetry: 'Thử gửi lại', + steerQueueSendNow: 'Bổ sung cho tác vụ hiện tại', + steerQueueWaiting: 'Sẽ gửi sau khi câu trả lời hiện tại hoàn tất', + steerQueueInjecting: 'Đang chờ áp dụng cập nhật', + messages: { + enterContent: 'Vui lòng nhập nội dung!', + replying: 'Đang phản hồi, vui lòng thử lại sau!', + steerAttachmentPending: 'Tệp đính kèm đang được tải lên. Vui lòng thử lại sau giây lát.', + steerHasAttachments: 'Không thể thêm tệp đính kèm khi đang trả lời. Vui lòng xóa tệp hoặc gửi sau khi hoàn tất.', + steerFailed: 'Không thể bổ sung tin nhắn. Vui lòng thử lại.', + steerPromoteFailed: 'Không thể gửi ngay. Vui lòng thử lại.', + steerRemoveFailed: 'Không thể xóa tin nhắn khỏi hàng đợi. Vui lòng thử lại.', + steerAlreadyInjected: 'Tin nhắn đã được áp dụng vào phản hồi đang chạy.', + steerFollowUpTimeout: 'Câu trả lời tiếp theo không bắt đầu kịp thời. Vui lòng gửi lại.', + steerNoActiveRun: 'Không có câu trả lời nào đang chạy. Vui lòng gửi trực tiếp.', + agentSwitchedOn: 'Đã chuyển sang Suy luận thông minh', + agentSwitchedOff: 'Đã chuyển sang Trả lời nhanh', + agentSelected: 'Đã chọn agent "{name}"', + webSearchNotConfigured: 'Chưa cấu hình công cụ tìm kiếm web. Vui lòng thiết lập nhà cung cấp và thông tin xác thực trong cài đặt.', + webSearchEnabled: 'Đã bật tìm kiếm web', + webSearchDisabled: 'Đã tắt tìm kiếm web', + sessionMissing: 'ID phiên không tồn tại', + messageMissing: 'Không tìm thấy ID tin nhắn. Vui lòng làm mới trang và thử lại.', + stopSuccess: 'Đã dừng tạo', + stopFailed: 'Dừng thất bại. Vui lòng thử lại.' + }, + webSearchDisabledByAgent: 'Tìm kiếm web bị tắt bởi Agent hiện tại', + kbLockedByAgent: 'Cấu hình kho tri thức bị khóa bởi Agent hiện tại', + kbDisabledByAgent: 'Kho tri thức bị tắt bởi Agent hiện tại', + modelLockedByAgent: 'Lựa chọn mô hình bị khóa bởi Agent hiện tại', + imageUploadDisabledByAgent: 'Tải ảnh lên chưa được bật cho Agent này', + goToAgentSettings: 'Đi tới cài đặt Agent' + }, + createChat: { + title: 'Xin chào, tôi là WeKnora — tri thức trong tầm tay bạn', + newSessionTitle: 'Phiên mới', + openProject: 'Chọn dự án', + clearProject: 'Xóa', + pickFailed: 'Không thể mở đường dẫn đã chọn', + messages: { + createFailed: 'Tạo phiên thất bại', + createError: 'Không thể tạo phiên, vui lòng thử lại sau' + } + }, + knowledgeList: { + create: 'Tạo kho tri thức', + subtitle: 'Quản lý và tổ chức các kho tri thức, hỗ trợ dạng tài liệu và FAQ', + sharedToOrgs: 'Đã chia sẻ tới {count} không gian', + uninitializedBanner: 'Một số kho tri thức chưa được khởi tạo. Vui lòng cấu hình thông tin mô hình trong cài đặt trước khi thêm tài liệu.', + empty: { + title: 'Chưa có kho tri thức nào', + description: 'Nhấp "Tạo kho tri thức" ở góc trên bên phải để bắt đầu.', + sharedTitle: 'Không có kho tri thức được chia sẻ', + sharedDescription: 'Bạn có thể tham gia một không gian được chia sẻ hoặc yêu cầu người khác chia sẻ kho tri thức', + favoritesTitle: 'Chưa có mục yêu thích', + favoritesDescription: 'Gắn dấu sao kho tri thức trên thẻ để thêm vào đây', + recentsTitle: 'Chưa có dữ liệu gần đây', + recentsDescription: 'Các kho tri thức đã mở gần đây sẽ hiển thị ở đây' + }, + delete: { + confirmTitle: 'Xác nhận xóa', + confirmMessage: 'Bạn có chắc chắn muốn xóa kho tri thức "{name}"? Thao tác này không thể hoàn tác.', + confirmButton: 'Xóa' + }, + menu: { + viewDetails: 'Xem chi tiết', + duplicate: 'Nhân bản' + }, + pin: { + pin: 'Ghim lên đầu', + unpin: 'Bỏ ghim', + pinSuccess: 'Đã ghim', + unpinSuccess: 'Đã bỏ ghim', + failed: 'Thao tác thất bại' + }, + sections: { + pinned: 'Đã ghim', + mine: 'Do tôi tạo', + tenantOthers: 'Không gian làm việc · Thành viên khác', + tenantReadonly: 'Không gian làm việc · Chỉ xem', + sharedByMe: 'Tôi đã chia sẻ', + sharedEditable: 'Được chia sẻ với tôi · Có thể chỉnh sửa', + sharedReadonly: 'Được chia sẻ với tôi · Chỉ xem' + }, + messages: { + deleted: 'Đã xóa kho tri thức', + deleteFailed: 'Xóa kho tri thức thất bại', + duplicateSuccess: 'Đã nhân bản kho tri thức (không bao gồm nội dung)', + duplicateFailed: 'Nhân bản kho tri thức thất bại' + }, + detail: { + title: 'Kho tri thức được chia sẻ', + sourceType: 'Nguồn', + sourceTypeKbShare: 'Kho tri thức chia sẻ trực tiếp tới không gian này', + sourceTypeAgent: 'Hiển thị qua Agent được chia sẻ', + sourceOrg: 'Không gian', + sourceFromAgent: 'Agent', + agentKbStrategy: 'Chiến lược kho tri thức của Agent', + agentKbStrategyAll: 'Tất cả kho tri thức', + agentKbStrategySelected: 'Kho tri thức đã chọn', + agentKbStrategyNone: 'Không dùng kho tri thức', + sharedAt: 'Thời gian chia sẻ', + myPermission: 'Quyền của tôi', + goToKb: 'Đi đến kho tri thức' + }, + features: { + knowledgeGraph: 'Đồ thị tri thức', + multimodal: 'Đa phương thức', + questionGeneration: 'Tạo câu hỏi tự động', + wiki: 'Wiki' + } + }, + embedPublish: { + create: 'Tạo kênh nhúng mới', + channelsTitle: 'Kênh nhúng', + disabled: 'Đã tắt', + empty: 'Chưa có kênh nhúng nào', + allowedOrigins: 'Nguồn được phép (Allowed origins)', + embedCode: 'Mã nhúng', + widgetCode: 'Mã widget', + copyCode: 'Sao chép mã', + channelKey: 'Khóa kênh (Channel key)', + channelKeyDesc: 'Mã bí mật dài hạn dùng để tích hợp trang web bên thứ ba — hãy lưu trữ an toàn', + channelKeyHint: 'Không thể tải khóa kênh. Hãy đóng và mở lại kênh này, hoặc tải lại trang.', + channelKeyLoadFailed: 'Tải khóa kênh thất bại', + channelKeyUnavailable: 'Khóa không khả dụng', + resetKeyTitle: 'Đặt lại khóa kênh', + resetKeyConfirmOk: 'Đặt lại', + resetKeyConfirmBody: 'Sau khi đặt lại, khóa cũ sẽ bị vô hiệu hóa ngay lập tức. Mọi mã nhúng đã triển khai cần dùng khóa mới để tiếp tục hoạt động. Thao tác này không thể hoàn tác.', + resetKeySuccess: 'Đã đặt lại khóa kênh — khóa mới đã hiển thị trong ô nhập liệu', + resetKeyFailed: 'Đặt lại khóa kênh thất bại', + copyChannelKeyTitle: 'Sao chép khóa kênh', + revealKey: 'Hiện khóa', + hideKey: 'Ẩn khóa', + createTitle: 'Tạo kênh nhúng mới', + name: 'Tên', + nameDesc: 'Dùng trong danh sách quản trị và định danh kênh', + namePlaceholder: 'Ví dụ: Hỗ trợ website', + nameDefaultHint: 'Mặc định là "{agent} · Web Embed" khi đã chọn Agent. Để trống khi lưu để dùng tên mặc định.', + defaultChannelName: 'Web Embed', + defaultChannelNameWithAgent: '{agent} · Web Embed', + welcomeMessage: 'Lời chào mừng', + welcomePlaceholder: 'Xin chào! Tôi có thể giúp gì cho bạn?', + welcomeMessageDesc: 'Hiển thị trong khung trò chuyện nhúng trước khi người dùng gửi tin nhắn đầu tiên; để trống để ẩn', + showSuggestedQuestions: 'Câu hỏi gợi ý', + showSuggestedQuestionsDesc: 'Hiển thị các câu hỏi gợi ý mở đầu từ cấu hình Agent và kho tri thức liên kết', + originsHint: 'Nhập tên miền trang web được phép nhúng kênh này (A), không phải địa chỉ WeKnora (B). Mỗi dòng một origin đầy đủ, ví dụ: https://shop.example.com; tối thiểu một nguồn. Hỗ trợ *.example.com.', + originsRequired: 'Yêu cầu ít nhất một nguồn được phép', + originsInvalid: 'Nguồn không hợp lệ: {origin}', + originsWildcardProd: 'Ký tự đại diện \'*\' không được phép trong môi trường Production', + originsPlaceholder: 'https://shop.example.com', + rateLimitLabel: 'Số yêu cầu mỗi phút', + rateLimitDesc: 'Số yêu cầu API tối đa mỗi phút cho từng IP truy cập; các yêu cầu vượt mức sẽ tạm thời bị từ chối. Mặc định: 30.', + rateLimitDayLabel: 'Giới hạn yêu cầu mỗi ngày', + rateLimitDayDesc: 'Tổng số yêu cầu cho phép mỗi ngày trên toàn kênh (tính trên mọi IP); hạn chế rủi ro chi phí nếu mã token bị lộ. Mặc định: 10000.', + publishTokenWarning: 'Mã token nhúng hiển thị dạng văn bản thuần trong mã nguồn trang — bất kỳ ai truy cập đều có thể xem được. Hãy coi đây là khóa công khai: không nhúng agent chứa dữ liệu nhạy cảm, luôn thiết lập danh sách tên miền cho phép, đặt giới hạn yêu cầu và tạo lại mã ngay nếu bị lộ.', + primaryColor: 'Màu chủ đạo', + pageTitle: 'Tiêu đề trang', + pageTitleDesc: 'Hiển thị trên thanh tiêu đề chat và tab trình duyệt; ưu tiên hơn tên kênh', + pageTitlePlaceholder: 'Trợ lý AI', + headerTitleMode: 'Tiêu đề đầu trang', + headerTitleModeChannel: 'Tiêu đề kênh cố định', + headerTitleModeSession: 'Theo tiêu đề phiên chat', + headerTitleModeDesc: 'Cố định: luôn hiển thị tiêu đề trang. Phiên chat: tự động tạo tiêu đề từ tin nhắn đầu tiên; tạm dùng tiêu đề trang trong lúc tạo.', + tokenHint: 'Không thể tải mã khóa kênh. Vui lòng đóng và mở lại kênh này.', + createdWithToken: 'Đã tạo kênh nhúng — mã khóa kênh hiển thị bên dưới', + created: 'Đã tạo kênh nhúng', + updated: 'Đã cập nhật kênh nhúng', + saveFailed: 'Lưu thất bại', + deleted: 'Đã xóa', + copied: 'Đã sao chép mã nhúng', + loadError: 'Tải thất bại', + missingChannel: 'Thiếu kênh nhúng hoặc mã token', + invalidChannel: 'Kênh nhúng không hợp lệ', + sessionFailed: 'Tạo phiên chat thất bại, vui lòng thử lại', + channelDisabled: 'Kênh nhúng này đã bị tắt. Kích hoạt lại tại Trình chỉnh sửa Agent → Nhúng trang web', + loading: 'Đang tải...', + tabIframe: 'iFrame', + tabWidget: 'Widget', + tabSecure: 'Chế độ bảo mật', + widgetPosition: 'Vị trí widget', + widgetPreview: 'Xem trước widget', + positionBottomRight: 'Dưới cùng bên phải', + positionBottomLeft: 'Dưới cùng bên trái', + positionTopRight: 'Trên cùng bên phải', + positionTopLeft: 'Trên cùng bên trái', + tokenCopied: 'Đã sao chép khóa kênh', + awaitingToken: 'Đang chờ trang chủ cung cấp mã token…', + preview: 'Xem trước', + previewIframeHint: 'Mô phỏng giao diện nhúng iframe trên trang ngoài (giống đoạn mã đã sao chép).', + previewWidgetHint: 'Mô phỏng widget nổi trên trang mẫu. Trên trang thực tế, trang chủ sẽ truyền token qua postMessage.', + previewMockPage: 'Trang chủ mẫu', + previewLoading: 'Đang tải xem trước…', + previewUnavailable: 'Không thể xem trước. Hãy đảm bảo kênh đã bật và Redis đang hoạt động.', + defaultChatTitle: 'Trợ lý AI', + newChat: 'Đoạn chat mới', + sectionChannel: 'Thông tin kênh', + sectionSecurity: 'Bảo mật & Giới hạn tần suất', + sectionCapabilities: 'Tính năng chat', + allowWebSearch: 'Hiển thị nút tìm kiếm web', + allowWebSearchDesc: 'Khi bật, người dùng sẽ thấy nút tìm kiếm web ở khung nhập và có thể tự bật/tắt; mặc định tắt. Nút chỉ xuất hiện nếu agent được liên kết đã bật tìm kiếm web.', + allowFileUpload: 'Cho phép tải tệp lên', + allowFileUploadDesc: 'Khi bật, người dùng có thể tải lên hình ảnh và tài liệu đính kèm. Yêu cầu agent được liên kết hỗ trợ tải ảnh.', + webhookUrl: 'URL Webhook', + webhookUrlPlaceholder: 'https://your-server.example.com/weknora/embed-events', + webhookUrlDesc: 'Không bắt buộc. WeKnora sẽ gửi sự kiện message_sent / message_received qua phương thức POST tới endpoint HTTPS này.', + webhookSecret: 'Khóa bí mật Webhook', + webhookSecretPlaceholder: 'Mã bí mật HMAC-SHA256 (tiêu đề X-WeKnora-Signature)', + webhookSecretKeep: 'Để trống để giữ nguyên khóa bí mật hiện tại', + webhookSecretDesc: 'Không bắt buộc. Khi thiết lập, nội dung yêu cầu sẽ được ký số để xác thực trên máy chủ của bạn.', + agentWebSearchDisabledHint: 'Agent này chưa bật tìm kiếm web. Nút tìm kiếm web chỉ hiển thị sau khi bạn kích hoạt trong cài đặt agent.', + agentImageUploadDisabledHint: 'Agent này chưa bật tải ảnh lên. Nút tải lên chỉ hiển thị sau khi bạn kích hoạt trong cài đặt agent.', + sectionAppearance: 'Giao diện', + sectionDeploy: 'Triển khai lên trang web', + sectionWebhook: 'Callback sự kiện', + stepChannel: 'Thông tin kênh', + stepSecurity: 'Bảo mật', + stepCapabilities: 'Tính năng', + stepAppearance: 'Giao diện', + stepWebhook: 'Webhook', + stepDeploy: 'Triển khai', + deployIntro: 'Chọn kiểu nhúng và dán đoạn mã bên dưới vào trang web của bạn. Xem hoặc tạo lại mã khóa kênh ở phía dưới khi cần thông tin xác thực.', + deployStepEmbed: 'Sao chép mã nhúng', + deployStepEmbedDesc: 'Chọn kiểu nhúng và dán đoạn mã vào trang web của bạn.', + embedIframeDesc: 'Nhúng toàn bộ giao diện chat vào một khu vực cố định trên trang.', + embedWidgetDesc: 'Nút mở nổi ở góc màn hình; nhấp để mở khung chat.', + embedSecureDesc: 'Khuyến nghị: mã token xuất bản lưu trên backend của bạn, trang web chỉ nhận token ngắn hạn, tránh để lộ khóa lâu dài ra trình duyệt.', + deployAfterSaveHint: 'Sau khi lưu, bạn có thể sao chép mã khóa kênh và mã nhúng tại đây.', + widgetTokenNote: 'Mã script của widget phải bao gồm mã khóa kênh; nhúng qua iframe sẽ tự động trao đổi thông tin xác thực khi tải.', + secureTokenNote: 'Trang web không cần chứa mã token xuất bản; trang sẽ trỏ tới endpoint cấp token trên backend của bạn (data-token-endpoint). Backend đổi token xuất bản lấy token ngắn hạn 30 phút và trả về cho trang; widget sẽ tự động làm mới trước khi hết hạn.', + secureServerLabel: 'Ví dụ endpoint cấp token phía máy chủ (token xuất bản lưu trên máy chủ)', + tabServerNode: 'Node.js', + tabServerGo: 'Go', + enabled: 'Bật kênh', + deleteConfirm: 'Xóa kênh nhúng này? Các đoạn mã đã nhúng trước đó sẽ ngừng hoạt động.', + defaultLocale: 'Ngôn ngữ mặc định', + defaultLocaleDesc: 'Ngôn ngữ giao diện khi người dùng mở chat; để trống sẽ theo trình duyệt hoặc phương thức setLocale() của widget.', + defaultLocaleBrowser: 'Mặc định theo trình duyệt / trang chủ' + }, + knowledgeEditor: { + activity: { + columns: { + time: 'Thời gian', + action: 'Hành động', + target: 'Đối tượng', + actor: 'Người thực hiện', + outcome: 'Kết quả' + }, + expanded: { + targetType: 'Loại đối tượng', + targetId: 'ID đối tượng', + actorId: 'ID người thực hiện', + apiKeyName: 'Tên API key', + apiKeyId: 'ID API key', + details: 'Chi tiết' + }, + drawer: { + sectionSummary: 'Tổng quan', + sectionIdentifiers: 'Định danh', + sectionTask: 'Thông tin tác vụ', + targetChange: 'Chi tiết thay đổi' + }, + systemActor: 'Hệ thống', + actorWithAPIKey: '{actor} · API Key · {name}', + actorAPIKey: 'API Key · {name}', + knowledgeBase: 'Kho tri thức', + countItems: '{count} mục', + titleWithCount: '{title} và {count} mục khác', + importSummary: 'Thành công {success} / Thất bại {failed} / Đã bỏ qua {skipped}', + targets: { + knowledge_base: 'Kho tri thức', + knowledge: 'Tri thức', + faq_entry: 'Mục FAQ', + knowledge_tag: 'Thẻ', + data_source: 'Nguồn dữ liệu', + knowledge_base_share: 'Chia sẻ', + knowledge_move: 'Di chuyển tri thức', + wiki: 'Wiki' + }, + detailFields: { + task_id: 'ID tác vụ', + trigger: 'Kích hoạt', + processing_status: 'Trạng thái xử lý', + source_kb_id: 'ID kho tri thức nguồn', + target_kb_id: 'ID kho tri thức đích', + sync_log_id: 'ID nhật ký đồng bộ', + mode: 'Chế độ', + attempt: 'Lần thử xử lý', + count: 'Số lượng mục', + total: 'Tổng số', + processed: 'Đã xử lý', + failed: 'Thất bại', + skipped: 'Đã bỏ qua', + failure_stage: 'Giai đoạn thất bại' + }, + actions: { + kb: { + created: 'Đã tạo kho tri thức', + updated: 'Đã cập nhật kho tri thức', + deleted: 'Đã xóa kho tri thức', + duplicated: 'Đã nhân bản kho tri thức', + clone_started: 'Bắt đầu nhân bản', + clone_completed: 'Nhân bản hoàn tất', + clone_failed: 'Nhân bản thất bại', + share_added: 'Đã thêm chia sẻ', + share_permission_changed: 'Đã thay đổi quyền chia sẻ', + share_removed: 'Đã gỡ chia sẻ' + }, + knowledge: { + created: 'Đã thêm tri thức', + updated: 'Đã cập nhật tri thức', + deleted: 'Đã xóa tri thức', + batch_deleted: 'Đã xóa hàng loạt tri thức', + reparse_started: 'Bắt đầu phân tích lại', + parse_canceled: 'Đã hủy phân tích', + move_started: 'Bắt đầu di chuyển tri thức', + move_completed: 'Di chuyển tri thức hoàn tất', + move_failed: 'Di chuyển tri thức thất bại' + }, + tag: { + created: 'Đã tạo thẻ', + updated: 'Đã cập nhật thẻ', + deleted: 'Đã xóa thẻ' + }, + datasource: { + created: 'Đã tạo nguồn dữ liệu', + updated: 'Đã cập nhật nguồn dữ liệu', + deleted: 'Đã xóa nguồn dữ liệu', + sync_started: 'Bắt đầu đồng bộ nguồn dữ liệu', + sync_completed: 'Đồng bộ nguồn dữ liệu hoàn tất', + sync_failed: 'Đồng bộ nguồn dữ liệu thất bại', + paused: 'Đã tạm dừng nguồn dữ liệu', + resumed: 'Đã tiếp tục nguồn dữ liệu' + }, + wiki: { + content_changed: 'Nội dung Wiki đã thay đổi' + }, + faq: { + import_started: 'Bắt đầu nhập FAQ', + import_completed: 'Nhập FAQ hoàn tất', + import_failed: 'Nhập FAQ thất bại' + } + }, + outcomes: { + accepted: 'Đã tiếp nhận', + success: 'Thành công', + failed: 'Thất bại', + partial: 'Một phần', + canceled: 'Đã hủy', + denied: 'Bị từ chối' + }, + detailValues: { + user: 'Người dùng khởi tạo', + manual: 'Thủ công', + schedule: 'Theo lịch', + system: 'Hệ thống', + pending: 'Đang chờ', + completed: 'Hoàn tất', + partial: 'Hoàn tất một phần', + canceled: 'Đã hủy', + failed: 'Thất bại', + enqueue: 'Xếp hàng tác vụ', + reuse_vectors: 'Dùng lại vector', + reparse: 'Phân tích lại', + viewer: 'Chỉ xem', + editor: 'Có thể chỉnh sửa', + admin: 'Quản trị', + append: 'Nối thêm', + replace: 'Thay thế' + }, + title: 'Hoạt động', + description: 'Các thay đổi quan trọng và tiến trình nền của kho tri thức này. Thời gian lưu trữ tuân theo chính sách Audit Log.', + allOutcomes: 'Tất cả kết quả', + allActions: 'Tất cả hành động', + refresh: 'Làm mới', + retry: 'Thử lại', + empty: 'Chưa có hoạt động nào', + emptyFiltered: 'Không có bản ghi hoạt động phù hợp', + clearFilters: 'Xóa bộ lọc', + loadingMore: 'Đang tải thêm…', + end: 'Không còn hoạt động cũ hơn', + loadFailed: 'Tải hoạt động thất bại' + }, + wikiBrowser: { + newPageBtn: 'Trang mới', + newPageTitle: 'Tạo trang wiki', + newPageTitleLabel: 'Tiêu đề', + newPageTitlePlaceholder: 'Nhập tiêu đề trang', + newPageSlugLabel: 'Slug (đường dẫn)', + newPageSlugPlaceholder: 'vd: concept/my-topic', + newPageSlugHint: 'Chữ cái/chữ số/dấu gạch ngang, dùng "/" để phân cấp; không thể thay đổi sau này', + newPageTypeLabel: 'Loại trang', + newPageContentLabel: 'Nội dung (tùy chọn)', + newPageMissingFields: 'Tiêu đề và slug là bắt buộc', + newPageSuccess: 'Đã tạo trang', + newPageFailed: 'Tạo trang thất bại', + revisionCurrent: 'Hiện tại', + revisionCurrentHint: 'Đây là phiên bản hiện tại. Chọn một phiên bản lịch sử ở bên trái để so sánh hoặc khôi phục.', + revisionSelectHint: 'Chọn một phiên bản ở bên trái', + revisionEmpty: 'Chưa có lịch sử — bản chụp sẽ tự động lưu khi nội dung thay đổi', + revisionDiff: 'So sánh với hiện tại', + revisionRaw: 'Nội dung gốc', + revisionDiffCaption: 'v{from} → v{to} (đỏ = bản này, xanh = hiện tại)', + revisionDiffIncremental: 'Thay đổi phiên bản', + revisionDiffCumulative: 'So với hiện tại', + revisionDiffBasisLabel: 'Chế độ so sánh', + revisionViewModeLabel: 'Chế độ xem', + revisionLatestChangeHint: 'Các thay đổi từ phiên bản trước đến hiện tại', + revisionIncrementalHint: 'Các thay đổi tạo nên v{ver}', + revisionInitialRange: 'Ban đầu → v{ver}', + revisionInitialCreationHint: 'Nội dung ban đầu khi tạo', + revisionCumulativeHint: 'Toàn bộ thay đổi từ phiên bản này đến hiện tại', + revisionDiffIncrementalCaption: 'v{from} → v{to} (phiên bản liền kề; đỏ = cũ, xanh = mới)', + revisionDiffCumulativeCaption: 'v{from} → v{to} (thay đổi tích luỹ đến hiện tại)', + revisionFirstVersionHint: 'Đây là phiên bản đầu tiên — không có phiên bản trước để so sánh.', + revisionDiffTitle: 'Tiêu đề', + revisionDiffSummary: 'Tóm tắt', + revisionDiffContent: 'Nội dung', + revisionDiffEmpty: 'Không có khác biệt về tiêu đề, tóm tắt hoặc nội dung so với bản hiện tại', + revisionLoadFailed: 'Không thể tải lịch sử phiên bản', + revisionNotRetained: 'Phiên bản này không có bản chụp được lưu hoặc đã bị dọn dẹp', + revisionNotRetainedRange: 'v{ver} · toàn bộ nội dung', + revisionNotRetainedHint: 'Không có bản chụp cho phiên bản trước v{prev} (các phiên bản trước khi nâng cấp không được lưu bản chụp; bản chụp cũ cũng có thể đã bị dọn bớt) — hiển thị toàn bộ nội dung của v{ver}.', + revertBtn: 'Khôi phục phiên bản này', + revertConfirm: 'Khôi phục về v{ver}? Nội dung hiện tại sẽ được lưu bản chụp trước, bạn vẫn có thể hoàn tác.', + revertSuccess: 'Đã khôi phục về v{ver}', + revertFailed: 'Khôi phục thất bại', + viewInGraph: 'Xem trên đồ thị', + editingBadge: 'Đang chỉnh sửa', + pageActions: 'Thao tác trang', + tabDocuments: 'Tài liệu', + tabGraph: 'Đồ thị', + tabGraphTip: 'Đồ thị liên kết giữa các trang Wiki. Đồ thị này KHÔNG PHẢI là Đồ thị tri thức thực thể - quan hệ được trích xuất bởi LLM trong "Cài đặt Kho tri thức → Đồ thị tri thức".', + searchPlaceholder: 'Tìm kiếm trang wiki...', + searchNoResults: 'Không tìm thấy trang phù hợp', + viewModeToggle: 'Chuyển chế độ xem thư mục', + viewTree: 'Dạng cây', + viewList: 'Dạng danh sách', + newRootFolder: 'Thư mục mới', + newSubfolder: 'Thư mục con mới', + folderActions: 'Thao tác thư mục', + folderNamePlaceholder: 'Nhập tên thư mục', + createFolderSuccess: 'Đã tạo thư mục', + createFolderFailed: 'Tạo thư mục thất bại', + movePageSuccess: 'Đã di chuyển trang', + movePageFailed: 'Di chuyển trang thất bại', + renameFolder: 'Đổi tên thư mục', + renameFolderSuccess: 'Đã đổi tên thư mục', + renameFolderFailed: 'Đổi tên thư mục thất bại', + deleteFolder: 'Xóa thư mục', + deleteFolderConfirm: 'Xóa thư mục "{name}"?', + deleteFolderSuccess: 'Đã xóa thư mục', + deleteFolderFailed: 'Xóa thư mục thất bại', + deleteFolderNotEmpty: 'Thư mục không trống. Vui lòng chuyển hoặc xóa các trang và thư mục con trước.', + moveFolderSuccess: 'Đã di chuyển thư mục', + moveFolderFailed: 'Di chuyển thư mục thất bại', + moveFolderIntoSelf: 'Không thể di chuyển thư mục vào chính nó hoặc thư mục con', + moveConfirm: 'Di chuyển tới "{target}"?', + moveConfirmTitle: 'Xác nhận di chuyển', + rootFolderLabel: 'Thư mục gốc', + filterSummary: 'Tóm tắt', + filterKnowledge: 'Tri thức', + filterEntity: 'Thực thể', + filterConcept: 'Khái niệm', + filterSynthesis: 'Tổng hợp', + filterComparison: 'So sánh', + legendFamiliar: 'Nguồn thường dùng', + emptyTitle: 'Chưa có trang wiki nào', + emptyDesc: 'Tải lên tài liệu và bật Wiki để tự động tạo các trang tri thức', + selectPageHint: 'Chọn một trang ở bên trái để xem nội dung', + version: 'v{ver}', + aliases: 'Tên gọi khác', + linkedFrom: 'Được liên kết từ', + sources: 'Tài liệu nguồn', + graphEmpty: 'Đang tải đồ thị...', + fitView: 'Vừa khung nhìn', + indexTitle: 'Mục lục', + loading: 'Đang tải…', + loadMoreShort: 'Xem thêm', + indexOverviewTag: 'Thư mục', + indexEmpty: 'Chưa có trang wiki nào. Vui lòng tải tài liệu lên trước.', + graphNoData: 'Chưa có dữ liệu đồ thị. Vui lòng tải tài liệu lên trước. (Giao diện này hiển thị liên kết giữa các trang Wiki, khác với Đồ thị tri thức thực thể - quan hệ trong "Cài đặt Kho tri thức → Đồ thị tri thức".)', + showArrows: 'Hiện mũi tên', + hideArrows: 'Ẩn mũi tên', + editBtn: 'Chỉnh sửa', + historyBtn: 'Lịch sử', + historyTitle: 'Lịch sử chỉnh sửa · {title}', + deletePageBtn: 'Xóa', + deletePageConfirm: 'Xóa trang "{title}"? Trang này sẽ bị xóa khỏi wiki.', + deletePageSuccess: 'Đã xóa trang', + deletePageFailed: 'Xóa trang thất bại', + editTitlePlaceholder: 'Tiêu đề trang', + editSummaryPlaceholder: 'Tóm tắt ngắn (hiển thị trong chỉ mục)', + editContentPlaceholder: 'Nội dung Markdown, hỗ trợ cú pháp [[wiki-link]]', + editSaveSuccess: 'Đã lưu trang', + editSaveFailed: 'Lưu thất bại', + editConflictHint: 'Xung đột lưu: trang đã được cập nhật lên v{ver} bởi người khác. Tải lại bản mới nhất (hủy bản nháp) hoặc ghi đè (bản cũ vẫn được lưu trong lịch sử).', + editConflictReload: 'Tải bản mới nhất', + editConflictOverwrite: 'Ghi đè', + editSourceUser: 'Chỉnh sửa thủ công', + editSourceAgent: 'AI chỉnh sửa', + editSourceRevert: 'Đã hoàn tác', + editSourcePipeline: 'Tự động tạo', + expandNeighbors: 'Mở rộng liên kết', + bloomNeighbors: 'Mở rộng phân nhánh', + growFrontier: 'Mở rộng biên ({count})', + growFrontierTitle: 'Mở rộng toàn bộ {count} nút viền nét đứt chỉ với một nhấp', + cardEgoTitle: 'Trọng tâm hiện tại', + cardOverviewTitle: 'Tổng quan kho tri thức', + cardOverviewPrimary: '{returned} / {total} nút', + cardOverviewHintTruncated: 'Nhấp đúp vào nút bất kỳ để tập trung vào đồ thị con', + cardOverviewHintFull: 'Đang hiển thị toàn bộ nút trong kho tri thức', + cardRelatedNodes: '{count} nút liên quan', + helpButtonTitle: 'Trợ giúp', + helpTitle: 'Thao tác trên canvas', + helpClickAction: 'Nhấp', + helpClickDesc: 'Mở chi tiết nút', + helpDblClickAction: 'Nhấp đúp', + helpDblClickDesc: 'Tập trung vào nút này', + helpShiftClickAction: 'Shift + nhấp', + helpShiftClickDesc: 'Bung các nút lân cận ra canvas', + helpHoverPlusAction: 'Rê chuột → ⊕', + helpHoverPlusDesc: 'Tương tự Shift + nhấp', + helpDragAction: 'Kéo nút', + helpDragDesc: 'Thay đổi vị trí nút', + helpPanAction: 'Kéo vùng trống', + helpPanDesc: 'Di chuyển canvas', + helpZoomAction: 'Cuộn chuột', + helpZoomDesc: 'Thu phóng canvas', + neighborsProgress: 'Hiển thị {visible} / {total} nút lân cận ({hidden} chưa tải)', + neighborsAllShown: 'Toàn bộ {total} nút lân cận đã hiển thị trên canvas (nhấp Mở rộng để xem đồ thị con của nút này)', + neighborsNone: 'Trang này không có nút lân cận liên kết', + neighborsCenterUnreachable: 'Hiển thị {visible} / {total} nút lân cận ({hidden} không khả dụng: liên kết hỏng, bị lọc hoặc đã xóa)', + neighborsOverviewHidden: 'Hiển thị {visible} / {total} nút lân cận ({hidden} nằm ngoài tổng quan — nhấp Mở rộng để chuyển đến đây)', + backToOverview: 'Quay lại tổng quan', + queueStatus: '{count} tác vụ đang chờ trong hàng đợi Wiki', + issueTitle: 'Trang này có {count} xung đột hoặc lỗi tri thức chưa xử lý', + issueFixBtn: 'AI tự sửa', + issueMixed: 'Thông tin hỗn tạp', + issueConflict: 'Xung đột dữ kiện', + issueOutdated: 'Lỗi thời', + issueAttention: 'Cần chú ý', + issueReportedBy: 'Báo cáo bởi {reporter}', + issueAiLinter: 'Trình kiểm tra AI', + issueIgnore: 'Bỏ qua báo động giả', + globalIssuesTitle: 'Vấn đề nội dung toàn cục chưa xử lý', + globalIssuesCount: '{count} vấn đề nội dung chưa xử lý', + globalIssuesEmpty: 'Không có vấn đề nội dung nào cần xử lý', + issuePagePrefix: 'Trang: ', + issueGoFix: 'Đi đến sửa', + fixAssistantTitle: 'Trợ lý sửa lỗi Wiki thông minh', + issueFixSuggestions: 'Gợi ý tối ưu nội dung ({count})', + issueFixSingle: 'Sửa', + fixStartError: 'Không thể khởi động trợ lý sửa lỗi', + issueFixPromptSingle: 'Vui lòng sửa vấn đề (ID: {id}) trên trang [[{slug}]].', + issueFixPromptAutoStart: 'Vui lòng sửa các vấn đề sau trên trang [[{slug}]]:', + tabGallery: 'Thư viện ảnh', + tabDocumentsTip: 'Tải lên và quản lý tài liệu nguồn', + tabWikiTip: 'Các trang Wiki được tự động biên soạn từ tài liệu', + tabGalleryTip: 'Duyệt toàn bộ hình ảnh được trích xuất từ tài liệu', + viewTabs: 'Chế độ xem kho tri thức', + gallery: { + title: 'Thư viện ảnh', + allImages: 'Tất cả hình ảnh', + count: '{count} hình ảnh', + countFiltered: '{count} kết quả phù hợp', + searchPlaceholder: 'Tìm kiếm chú thích hoặc văn bản trong ảnh', + filters: 'Bộ lọc', + clearFilters: 'Xóa bộ lọc', + searchIn: 'Tìm kiếm trong', + searchInHint: 'Từ khóa chỉ khớp với nội dung được đánh dấu', + attrSection: 'Thuộc tính hình ảnh', + attrHint: '"Ẩn" sẽ loại bỏ các ảnh có giá trị này; "Luôn hiển thị" giữ lại ảnh ngay cả khi quy tắc khác ẩn đi', + verdictDefault: 'Bất kỳ', + verdictOff: 'Ẩn', + verdictOn: 'Luôn hiển thị', + keywordsPlaceholder: 'Phân tách các từ khóa bằng dấu phẩy', + noAttrs: 'Không có thuộc tính để lọc', + sort: 'Sắp xếp', + sortField: 'Sắp xếp theo', + sortOrder: 'Thứ tự', + orderAsc: 'Tăng dần', + orderDesc: 'Giảm dần', + empty: 'Chưa có hình ảnh nào để duyệt', + emptyHint: 'Hình ảnh trong tài liệu sẽ xuất hiện tại đây sau khi bóc tách xong', + emptyFiltered: 'Không có hình ảnh nào khớp với bộ lọc', + imageLoadError: 'Không thể tải hình ảnh', + noCaption: 'Không có chú thích', + noOcr: 'Không nhận diện được văn bản', + caption: 'Chú thích', + ocr: 'Văn bản trong ảnh (OCR)', + attributes: 'Thuộc tính', + source: 'Tài liệu nguồn', + details: 'Chi tiết', + dimensions: 'Kích thước', + status: 'Trạng thái', + openSource: 'Mở tài liệu nguồn', + copy: 'Sao chép', + zoomIn: 'Phóng to (+)', + zoomOut: 'Thu nhỏ (-)', + zoomReset: 'Vừa khung hình (0)', + actualSize: 'Kích thước thực', + rotate: 'Xoay (R)', + download: 'Tải về', + openOriginal: 'Mở trong tab mới', + toggleInfo: 'Thông tin ảnh (I)', + viewerClose: 'Đóng (Esc)', + prev: 'Trước (←)', + next: 'Tiếp (→)', + attr: { + builtin_caption: 'Chú thích', + builtin_caption_description: 'Mô tả hình ảnh do mô hình tạo ra.', + builtin_ocr_text: 'Văn bản OCR', + builtin_ocr_text_description: 'Văn bản trích xuất từ hình ảnh bằng OCR.', + builtin_created_at: 'Thời gian tạo', + builtin_created_at_description: 'Thời điểm Chunk tài liệu chứa ảnh được tạo.', + builtin_updated_at: 'Thời gian cập nhật', + builtin_updated_at_description: 'Thời điểm Chunk tài liệu chứa ảnh được cập nhật lần cuối.', + builtin_is_enabled: 'Kích hoạt', + builtin_is_enabled_description: 'Xác định xem Chunk tài liệu chứa ảnh có tham gia truy xuất hay không.', + builtin_is_enabled_value_true: 'Đã kích hoạt', + builtin_is_enabled_value_false: 'Đã vô hiệu hóa' + } + } + }, + titleCreate: 'Tạo kho tri thức', + titleEdit: 'Cài đặt kho tri thức', + navGroups: { + basic: 'Cơ bản', + processing: 'Lập chỉ mục & Phân tích', + data: 'Lưu trữ & Dữ liệu', + integration: 'Xuất bản', + management: 'Quản trị & Nhật ký' + }, + sidebar: { + basic: 'Thông tin cơ bản', + models: 'Cấu hình mô hình', + vectorStore: 'Bộ lưu trữ vector', + chunking: 'Cài đặt Chunk', + storage: 'Công cụ lưu trữ', + advanced: 'Cài đặt nâng cao', + faq: 'Cài đặt FAQ', + graph: 'Đồ thị tri thức', + multimodal: 'Xử lý hình ảnh', + asr: 'Âm thanh', + datasource: 'Nguồn dữ liệu', + share: 'Chia sẻ', + activity: 'Hoạt động' + }, + errors: { + vectorStoreBindingInvalid: 'Không thể dùng bộ lưu trữ vector đã chọn. Vui lòng chọn bộ lưu trữ khác hoặc dùng mặc định của hệ thống.', + vectorStoreUnavailable: 'Bộ lưu trữ vector đã chọn hiện không khả dụng. Kiểm tra kết nối tại Cài đặt → Bộ lưu trữ vector.' + }, + basic: { + title: 'Thông tin cơ bản', + description: 'Cấu hình tên và mô tả kho tri thức', + kbId: 'ID kho tri thức', + kbIdDesc: 'Dùng ID này để gọi kho tri thức qua API', + typeLabel: 'Loại kho tri thức', + typeDocument: 'Dựa trên tài liệu', + typeFAQ: 'Hỏi đáp FAQ', + typeDescription: 'FAQ phù hợp cho bộ dữ liệu Q&A có cấu trúc; Tài liệu hỗ trợ phân tích và Chunk tệp; Wiki tự động tạo các trang tri thức liên kết qua LLM.', + nameLabel: 'Tên kho tri thức', + namePlaceholder: 'Nhập tên kho tri thức', + descriptionLabel: 'Mô tả kho tri thức', + descriptionPlaceholder: 'Nhập mô tả kho tri thức (tùy chọn)', + profile: { + title: 'Mô tả do AI tạo', + hint: 'Được trích xuất từ hồ sơ tài liệu. Không ghi đè mô tả thủ công ở trên; Agent tham chiếu cả hai để định tuyến câu hỏi chính xác.', + empty: 'Chưa tạo. Tải tài liệu lên, chờ tóm tắt hoàn tất và bấm nút bên dưới.', + noDocuments: 'Chưa có tài liệu nào được xử lý trong kho tri thức này.', + questions: 'Câu hỏi tiêu biểu', + generate: 'Tạo mô tả bằng AI', + regenerate: 'Tạo lại', + adopt: 'Áp dụng làm mô tả', + generated: 'Đã tạo mô tả AI', + generateFailed: 'Tạo mô tả AI thất bại', + adopted: 'Đã sao chép vào mô tả; lưu để áp dụng', + failed: 'Lần tạo gần nhất thất bại: {error}', + generatedAt: 'Tạo lúc {time} · dựa trên {count} tài liệu' + } + }, + wiki: { + title: 'Cài đặt Wiki', + synthesisModelLabel: 'Mô hình tổng hợp Wiki', + synthesisModelPlaceholder: 'Chọn mô hình LLM để tạo Wiki', + synthesisModelTip: 'Mặc định sử dụng mô hình tóm tắt nếu để trống', + extractionGranularityLabel: 'Độ chi tiết trích xuất', + contentInstructionsLabel: 'Chỉ dẫn nội dung Wiki', + contentInstructionsTip: 'Điều chỉnh trọng tâm và văn phong cho bản tóm tắt, trang và chỉ mục. Các quy tắc trích dẫn, hợp nhất và tính xác thực do hệ thống kiểm soát. Xử lý lại nội dung để áp dụng.', + contentInstructionsPlaceholder: 'Ví dụ: văn phong thẩm định pháp lý, tập trung vào người phụ trách, tiến độ và rủi ro…', + extractionInstructionsLabel: 'Trọng tâm trích xuất Wiki', + extractionInstructionsTip: 'Mô tả các thực thể và khái niệm chuyên ngành cần ưu tiên trích xuất (vẫn tuân theo định dạng JSON và trích dẫn hệ thống).', + extractionInstructionsPlaceholder: 'Ví dụ: ưu tiên sản phẩm, phiên bản, tổ chức, người phụ trách và khái niệm kỹ thuật cốt lõi…', + extractionGranularityTip: 'Quy định số lượng thực thể/khái niệm Wiki trích xuất trên mỗi tài liệu. Càng chi tiết = chỉ mục càng cô đọng, càng bao quát = nội dung càng toàn diện', + granularityFocused: 'Trọng tâm', + granularityStandard: 'Tiêu chuẩn', + granularityExhaustive: 'Toàn diện', + granularityFocusedHint: 'Chỉ trích xuất các chủ thể chính (ví dụ: CV chỉ lấy ứng viên và dự án). Tinh gọn nhất, có thể bỏ sót thực thể phụ.', + granularityStandardHint: 'Chủ thể chính cùng các thực thể/khái niệm phụ được nhắc tới nhiều. Bỏ qua thuật ngữ nhắc thoáng qua. Khuyên dùng.', + granularityExhaustiveHint: 'Trích xuất mọi thực thể và khái niệm, bao gồm cả công cụ/công nghệ chỉ nhắc thoáng qua. Phù hợp làm bảng thuật ngữ.' + }, + indexing: { + title: 'Chiến lược lập chỉ mục', + description: 'Cấu hình quy trình xử lý tài liệu. Mỗi phương thức có thể bật hoặc tắt độc lập.', + searchTitle: 'Tìm kiếm RAG', + searchDesc: 'Chunk, Embedding và lập chỉ mục từ khóa để truy xuất kết hợp', + wikiTitle: 'Kho tri thức Wiki', + wikiDesc: 'Tự động tạo các trang wiki liên kết để xây dựng hệ thống tri thức có cấu trúc', + graphTitle: 'Đồ thị tri thức', + graphDesc: 'Trích xuất thực thể và mối quan hệ để xây dựng đồ thị phục vụ truy xuất theo đồ thị', + atLeastOne: 'Phải bật ít nhất một chiến lược lập chỉ mục', + embeddingRequired: 'Tìm kiếm RAG yêu cầu mô hình Embedding', + lockedTip: 'Không thể đổi chiến lược lập chỉ mục khi kho tri thức đã có dữ liệu. Vui lòng làm trống kho tri thức trước.', + rebuildConfirmTitle: 'Lập lại chỉ mục', + rebuildConfirmBody: 'Chiến lược lập chỉ mục đã thay đổi. Bạn có muốn xử lý lại {count} tài liệu hiện có không? Quá trình này có thể mất chút thời gian.', + rebuildSuccess: 'Đã gửi tác vụ lập lại chỉ mục cho {count} tài liệu', + rebuildSkip: 'Bạn có thể lập lại chỉ mục thủ công sau tại mục Nguồn dữ liệu' + }, + buttons: { + create: 'Tạo kho tri thức', + save: 'Lưu cấu hình', + saveAndClose: 'Lưu và đóng' + }, + footer: { + instantEffect: 'Thay đổi trên trang này có hiệu lực ngay; không cần lưu' + }, + postCreateHint: { + title: 'Tạo thành công', + footer: 'Tiếp tục chỉnh cài đặt, cấu hình chia sẻ và nguồn dữ liệu, sau đó nhấp "Lưu và đóng".', + followUpDesc: 'Cấu hình nguồn dữ liệu ở bên trái, hoặc dùng Quản lý chia sẻ để phát hành vào không gian làm việc' + }, + share: { + description: 'Chia sẻ kho tri thức với không gian làm việc để thành viên truy cập và sử dụng', + hintTitle: 'Lưu ý chia sẻ', + addShare: 'Chia sẻ', + unshareConfirm: 'Bạn có chắc muốn hủy chia sẻ khỏi "{name}"?', + tip1: 'Sau khi chia sẻ, thành viên không gian làm việc sẽ truy cập kho tri thức này theo phân quyền được cấp', + tip2: 'Quyền chỉnh sửa cho phép sửa nội dung; Quyền chỉ đọc chỉ cho phép truy xuất và hỏi đáp' + }, + messages: { + loadModelsFailed: 'Tải danh sách mô hình thất bại', + loadDataFailed: 'Tải dữ liệu kho tri thức thất bại', + notFound: 'Không tìm thấy kho tri thức', + nameRequired: 'Vui lòng nhập tên kho tri thức', + summaryRequired: 'Vui lòng chọn mô hình tóm tắt', + multimodalInvalid: 'Xác thực cấu hình đa phương thức thất bại', + createSuccess: 'Tạo kho tri thức thành công', + createFailed: 'Tạo kho tri thức thất bại', + missingId: 'Thiếu ID kho tri thức', + buildDataFailed: 'Tạo dữ liệu gửi đi thất bại', + updateSuccess: 'Lưu cấu hình thành công', + indexModeRequired: 'Vui lòng chọn chế độ lập chỉ mục cho kho tri thức FAQ', + storageChangeConfirm: 'Kho tri thức này đã có tệp. Việc đổi bộ lưu trữ có thể làm mất quyền truy cập các tệp cũ. Bạn có muốn tiếp tục?' + }, + document: { + title: 'Quản lý tài liệu', + subtitle: 'Nhấp hoặc kéo thả để tải lên; hệ thống tự động phân tích đa định dạng và Chunk thông minh để phục vụ tìm kiếm' + }, + faq: { + title: 'Cấu hình FAQ', + subtitle: 'Quản lý mục FAQ với tính năng nhập hàng loạt, chỉnh sửa và kiểm thử tìm kiếm', + description: 'Cấu hình chiến lược lập chỉ mục và hướng dẫn cho kho tri thức dạng FAQ', + indexModeLabel: 'Chế độ lập chỉ mục', + indexModeDescription: 'Chỉ lập chỉ mục câu hỏi giúp tăng độ chính xác; câu hỏi + câu trả lời giúp tăng độ bao phủ.', + questionIndexModeLabel: 'Chế độ lập chỉ mục câu hỏi', + questionIndexModeDescription: 'Kết hợp: Câu hỏi chuẩn và câu hỏi tương tự lập chỉ mục cùng nhau. Phân tách: Từng câu hỏi lập chỉ mục riêng để truy xuất chính xác hơn nhưng tốn dung lượng hơn.', + entryGuide: 'Mỗi mục FAQ gồm câu hỏi chính, câu hỏi tương tự, ví dụ phủ định và các câu trả lời. Quản lý trong chi tiết kho tri thức FAQ.', + tagDesc: 'Chọn thẻ cho mục FAQ', + tagPlaceholder: 'Chọn thẻ', + modes: { + questionOnly: 'Chỉ câu hỏi', + questionAnswer: 'Câu hỏi + câu trả lời', + combined: 'Kết hợp', + separate: 'Phân tách' + }, + standardQuestion: 'Câu hỏi chính', + standardQuestionDesc: 'Thiết lập cách diễn đạt chuẩn — đây là cách hỏi phổ biến nhất của người dùng.', + answers: 'Câu trả lời', + answersDesc: 'Cung cấp nội dung trả lời đầy đủ và chính xác. Có thể thêm nhiều câu trả lời cho các ngữ cảnh khác nhau.', + similarQuestions: 'Câu hỏi tương tự', + similarQuestionsDesc: 'Thêm các câu hỏi có cùng ý nghĩa nhưng khác cách diễn đạt để hệ thống khớp truy vấn tốt hơn.', + negativeQuestions: 'Ví dụ phủ định', + negativeQuestionsDesc: 'Thêm các câu hỏi không nên khớp với câu trả lời này để loại trừ kết quả sai.', + editorCreate: 'Tạo mục FAQ', + editorEdit: 'Chỉnh sửa mục FAQ', + answerPlaceholder: 'Nhập nội dung câu trả lời (hỗ trợ nhiều dòng), nhấn Ctrl+Enter hoặc bấm nút để thêm', + similarPlaceholder: 'Nhập câu hỏi tương tự và nhấn biểu tượng dấu cộng để thêm', + negativePlaceholder: 'Nhập ví dụ phủ định và nhấn biểu tượng dấu cộng để thêm', + answerRequired: 'Vui lòng nhập ít nhất một câu trả lời', + emptyTitle: 'Chưa có mục FAQ nào', + emptyDesc: 'Nhấn "Tạo mục FAQ" ở trên để bắt đầu', + searchPlaceholder: 'Tìm kiếm câu hỏi chuẩn...', + searchTest: 'Thử nghiệm tìm kiếm', + createGroup: 'Thêm mới', + searchTestTitle: 'Thử nghiệm tìm kiếm FAQ', + queryLabel: 'Truy vấn', + queryPlaceholder: 'Nhập câu hỏi cần tìm', + vectorThresholdDesc: 'Khoảng 0-1, mặc định 0.7', + matchCountLabel: 'Số lượng kết quả', + matchCountDesc: 'Khoảng 1-50, mặc định 10', + searchButton: 'Tìm kiếm', + searching: 'Đang tìm kiếm...', + searchResults: 'Kết quả tìm kiếm', + noResults: 'Không tìm thấy mục FAQ phù hợp', + matchedQuestion: 'Đã khớp', + matchTypeEmbedding: 'Khớp theo vector', + matchTypeKeywords: 'Khớp theo từ khóa', + similarityThresholdLabel: 'Ngưỡng tương đồng', + statusEnabled: 'Đang bật', + statusDisabled: 'Đã tắt', + statusEnableSuccess: 'Đã bật mục FAQ', + statusDisableSuccess: 'Đã tắt mục FAQ', + statusUpdateFailed: 'Cập nhật trạng thái thất bại', + recommended: 'Gợi ý', + recommendedEnabled: 'Đã bật gợi ý', + recommendedDisabled: 'Đã tắt gợi ý', + recommendedDisableSuccess: 'Đã tắt gợi ý cho mục FAQ', + recommendedUpdateFailed: 'Cập nhật trạng thái gợi ý thất bại', + batchUpdateTag: 'Gán thẻ hàng loạt', + batchUpdateTagTip: 'Gán thẻ cho {count} mục đã chọn', + batchEnable: 'Bật mục đã chọn', + batchDisable: 'Tắt mục đã chọn', + batchDelete: 'Xóa mục đã chọn', + confirmBatchDelete: 'Xóa {count} mục FAQ đã chọn? Thao tác này không thể hoàn tác.', + confirmDelete: 'Xóa mục FAQ này? Thao tác này không thể hoàn tác.', + batchDeleteSuccess: 'Đã xóa {count} mục FAQ' + }, + faqImport: { + title: 'Nhập FAQ hàng loạt', + modeLabel: 'Chế độ nhập', + appendMode: 'Thêm tiếp', + replaceMode: 'Ghi đè mục hiện có', + fileLabel: 'Chọn tệp', + fileTip: 'Hỗ trợ JSON / CSV / Excel. Tiêu đề cột CSV/Excel: Tag (bắt buộc), Question (bắt buộc), Similar Questions (tùy chọn, phân tách bằng ##), Negative Questions (tùy chọn, phân tách bằng ##), Bot Answers (bắt buộc, phân tách bằng ##), Reply All (tùy chọn, mặc định FALSE), Disabled (tùy chọn, mặc định FALSE), Exclude from Recommendations (tùy chọn, mặc định FALSE). Hỗ trợ cả tiêu đề cũ "Category" và định dạng cũ (standard_question, answers, similar_questions, negative_questions).', + clickToUpload: 'Nhấn để tải tệp lên', + dragDropTip: 'hoặc kéo thả tệp vào đây', + importButton: 'Nhập FAQ', + deleteSuccess: 'Đã xóa các mục đã chọn', + previewCount: 'Đã phân tích {count} mục', + previewMore: 'Còn {count} mục khác chưa hiển thị', + importSuccess: 'Nhập dữ liệu thành công', + parseFailed: 'Phân tích tệp thất bại', + invalidJSON: 'Định dạng JSON không hợp lệ', + unsupportedFormat: 'Định dạng tệp không được hỗ trợ', + selectFile: 'Vui lòng chọn tệp để nhập', + downloadExample: 'Tải tệp mẫu', + downloadExampleJSON: 'Tải mẫu JSON', + downloadExampleCSV: 'Tải mẫu CSV', + downloadExampleExcel: 'Tải mẫu Excel' + }, + faqExport: { + exportButton: 'Xuất dữ liệu', + exportCSV: 'Xuất CSV', + exportJSON: 'Xuất JSON', + exportSuccess: 'Xuất dữ liệu thành công', + exportFailed: 'Xuất dữ liệu thất bại' + }, + models: { + title: 'Cấu hình mô hình', + description: 'Chọn mô hình AI phù hợp cho kho tri thức', + llmLabel: 'Mô hình LLM', + llmDesc: 'Mô hình ngôn ngữ lớn dùng để tóm tắt và tạo bản trích yếu (tùy chọn)', + llmPlaceholder: 'Chọn mô hình LLM (tùy chọn)', + embeddingLabel: 'Mô hình Embedding', + embeddingDesc: 'Mô hình embedding dùng để Embedding văn bản', + embeddingPlaceholder: 'Chọn mô hình embedding', + embeddingLocked: 'Kho tri thức đã chứa tệp. Không thể thay đổi mô hình embedding', + embeddingOptional: '(Tùy chọn)', + embeddingWikiOptionalDesc: 'Tùy chọn. Khi thiết lập, hệ thống sẽ so khớp độ tương đồng để phân loại thư mục Wiki, giúp trang mới tái sử dụng thư mục hiện có tốt hơn; nếu không sẽ sử dụng toàn bộ cây thư mục.' + }, + chunking: { + title: 'Cài đặt Chunk', + description: 'Kiểm soát cách chia nhỏ tài liệu trước khi Embedding. Mặc định phù hợp với đa số trường hợp — chỉ điều chỉnh khi chất lượng truy xuất chưa tối ưu.', + sizeLabel: 'Kích thước đoạn', + sizeDescription: 'Số ký tự tối đa mỗi đoạn (100–4000). Mặc định 512 ≈ 100–130 token tiếng Anh. Đoạn nhỏ hơn cho FAQ (200–400), lớn hơn cho tài liệu tường thuật (1000–2000).', + characters: 'ký tự', + overlapLabel: 'Độ gối đoạn', + overlapDescription: 'Số ký tự trùng lặp giữa các đoạn liền kề (0–500). Mặc định 80 ≈ 15% kích thước đoạn — mức tối ưu theo nghiên cứu. Dùng 0 cho FAQ/dữ liệu có cấu trúc, 150–200 cho văn bản dài.', + separatorsLabel: 'Ký tự phân cách', + separatorsDescription: 'Ký tự hoặc chuỗi ký tự ưu tiên khi cắt đoạn. Ký tự có độ ưu tiên cao hơn sẽ được áp dụng trước; thứ tự mặc định ưu tiên đoạn văn → câu → dấu câu.', + separatorsPlaceholder: 'Chọn hoặc tùy chỉnh ký tự phân cách', + separators: { + doubleNewline: 'Xuống dòng đôi ()', + singleNewline: 'Xuống dòng đơn ()', + periodCn: 'Dấu chấm tiếng Trung (。)', + exclamationCn: 'Dấu chấm than (!)', + questionCn: 'Dấu chấm hỏi (?)', + semicolonCn: 'Dấu chấm phẩy tiếng Trung (;)', + semicolonEn: 'Dấu chấm phẩy (;)', + space: 'Dấu cách ( )' + }, + parentChildLabel: 'Chunk Cha - Con', + parentChildDescription: 'Chunk hai cấp: đoạn con nhỏ dùng để khớp vector (chính xác), đoạn cha lớn hơn gửi đến LLM (giàu ngữ cảnh). Khuyên dùng cho tài liệu dài (>10 trang); bỏ qua với FAQ ngắn để tiết kiệm bộ lưu trữ.', + parentChunkSizeLabel: 'Kích thước đoạn cha', + parentChunkSizeDescription: 'Kích thước đoạn ngữ cảnh gửi đến LLM (512–8192). Mặc định 4096 ≈ 1000 token tiếng Anh, phù hợp với hầu hết Context Window LLM hiện đại.', + childChunkSizeLabel: 'Kích thước đoạn con', + childChunkSizeDescription: 'Kích thước đoạn dùng để khớp vector (64–2048). Mặc định 384 ≈ 80 token — kích thước tối ưu cho mô hình embedding dạng sentence-transformer / BGE.', + strategyLabel: 'Chiến lược Chunk', + strategyDescription: 'Chọn cách chia nhỏ tài liệu. Chế độ Tự động sẽ phân tích tài liệu và chọn chiến lược tối ưu nhất.', + strategyPlaceholder: 'Chọn chiến lược Chunk (mặc định chia theo độ dài)', + strategies: { + auto: { + label: 'Tự động', + tooltip: 'Tự động chọn chia theo tiêu đề, cấu trúc hoặc độ dài cho từng tệp tải lên.' + }, + heading: { + label: 'Theo tiêu đề', + tooltip: 'Chia tại các tiêu đề Markdown (#, ##, ###); mỗi đoạn giữ nguyên phân cấp tiêu đề. Tối ưu cho Markdown có cấu trúc rõ ràng.' + }, + heuristic: { + label: 'Theo cấu trúc', + tooltip: 'Chia theo dấu hiệu cấu trúc: ngắt trang, đề mục đánh số, dấu phân chương (DE/EN/ZH), tiêu đề viết hoa. Lý tưởng cho PDF không có tiêu đề Markdown.' + }, + legacy: { + label: 'Theo độ dài', + tooltip: 'Bỏ qua cấu trúc; chia đệ quy theo số ký tự và dấu phân cách. Dùng khi Chunk theo cấu trúc hoạt động không như ý.' + } + }, + overlapWarning: 'Độ chồng lặp quá lớn so với kích thước đoạn — nội dung giữa các đoạn sẽ bị trùng lặp nhiều.', + advancedLabel: 'Tùy chọn nâng cao', + tokenLimitLabel: 'Giới hạn token mỗi đoạn', + tokenLimitDescription: 'Giới hạn token tối đa mỗi đoạn (0–8192). 0 = tắt (chỉ tính theo ký tự). Bật khi mô hình embedding có giới hạn token nhỏ: 200 cho MiniLM (256 tok), 400 cho BGE/Cohere (512 tok). Mô hình hiện đại (OpenAI, Voyage, Jina-v3) hỗ trợ >2000 token — nên để 0.', + languagesLabel: 'Gợi ý ngôn ngữ', + languagesDescription: 'Giới hạn nhận diện cấu trúc theo ngôn ngữ chọn trước (DE/EN/ZH). Để trống = tự phát hiện. Chọn cố định cho kho dữ liệu đơn ngữ để tránh nhận diện nhầm.', + languagesPlaceholder: 'Tự động phát hiện', + languageOptions: { + de: 'Tiếng Đức', + en: 'Tiếng Anh', + zh: 'Tiếng Trung' + }, + debug: { + toggle: 'Xem trước Chunk', + toggleHint: 'Chạy thử bộ Chunk trên văn bản mẫu mà không cần tải lại tệp', + sampleLabel: 'Văn bản mẫu', + samplePlaceholder: 'Dán đoạn Markdown hoặc văn bản thuần để xem kết quả Chunk với cấu hình hiện tại…', + presetLabel: 'Mẫu có sẵn:', + samples: { + markdown: 'Tài liệu Markdown', + faq: 'Danh sách FAQ', + chapter: 'Chương sách PDF', + plain: 'Văn bản thuần' + }, + runButton: 'Chạy xem trước', + loading: 'Đang Chunk văn bản mẫu…', + errorPrefix: 'Xem trước thất bại', + selectedTier: 'Chiến lược đã chọn', + rejected: 'Chiến lược bị loại bỏ', + contextHeader: 'Tiêu đề ngữ cảnh', + fallbackWarning: 'Không khớp chiến lược cấu trúc — nội dung chưa thể Chunk thông minh với cấu hình hiện tại', + profile: { + lines: 'dòng', + chars: 'ký tự', + headings: 'tiêu đề Markdown', + pageBreaks: 'dấu ngắt trang', + chapterMarkers: 'dấu phân chương', + languages: 'ngôn ngữ' + }, + stats: { + chunks: 'đoạn', + truncated: 'đã rút gọn; tổng số {total}' + } + } + }, + advanced: { + multimodal: { + descriptionLanguageAuto: 'Theo ngôn ngữ tài liệu', + customInstructionsLabel: 'Hướng dẫn xử lý hình ảnh', + customInstructionsDescription: 'Bổ sung ưu tiên xử lý hình ảnh trong khi vẫn giữ nguyên định dạng OCR và Markdown', + customInstructionsPlaceholder: 'Ví dụ: ưu tiên bảng tên, mã model, mã lỗi và đơn vị trong bảng…', + label: 'Tính năng đa phương thức', + description: 'Bật khả năng hiểu nội dung đa phương thức như hình ảnh', + vllmLabel: 'Mô hình thị giác VLLM', + vllmDescription: 'Mô hình thị giác-ngôn ngữ bắt buộc để xử lý đa phương thức', + vllmPlaceholder: 'Chọn mô hình VLLM (bắt buộc)', + descriptionLanguageLabel: 'Ngôn ngữ mô tả hình ảnh', + descriptionLanguageDescription: 'Để trống để dùng ngôn ngữ của tài liệu thay vì mặc định tiếng Trung', + imageAttrsLabel: 'Quan sát thuộc tính hình ảnh', + imageAttrsDescription: 'Khi bật, mỗi hình ảnh trước tiên được quan sát thuộc tính và mô tả, sau đó thuộc tính sẽ quyết định xem có chạy OCR văn bản trong ảnh hay không. Khi tắt, chế độ cơ bản áp dụng: mọi hình ảnh đều được mô tả và chạy OCR.', + imageAttrsSchemaLabel: 'Các thuộc tính hình ảnh có thể quan sát', + imageAttrsSchemaDescription: 'Mô hình quan sát các thuộc tính bên dưới (do registry backend định nghĩa) để điều khiển chính sách OCR', + imageAttrsOcrConditions: 'Kích hoạt OCR dựa trên điều kiện thuộc tính quan sát được', + imageAttrsOcrConditionsDesc: 'Khi các thuộc tính quan sát được khớp với các điều kiện bên dưới, OCR sẽ chạy trên hình ảnh', + imageAttrsOcrOnUnobserved: 'Chạy OCR khi quan sát thuộc tính ảnh thất bại', + imageAttrsOcrOnUnobservedDesc: 'Khi mô hình không nhận diện chính xác thuộc tính ảnh, OCR sẽ chạy mặc định để không bỏ sót nội dung văn bản; tắt đi để bỏ qua. (Mô hình thị giác nhỏ như 4B hoặc Prompt hướng dẫn tùy chỉnh xung đột với System Prompt có thể khiến việc quan sát thất bại; từ 8B trở lên hiếm khi lỗi, khuyến nghị giữ bật)', + imagePipelineKbNote: 'Mặc định tuân theo cài đặt kho tri thức; điều chỉnh phù hợp cho tác vụ này' + }, + title: 'Cài đặt nâng cao', + description: 'Cấu hình tự động tạo câu hỏi và các tính năng nâng cao khác', + questionGeneration: { + label: 'AI tạo câu hỏi', + description: 'Sử dụng LLM tạo các câu hỏi liên quan cho từng đoạn khi xử lý tài liệu để tăng độ bao phủ truy xuất. Thao tác này sẽ làm tăng thời gian xử lý tài liệu.', + countLabel: 'Số lượng câu hỏi', + countDescription: 'Số câu hỏi tạo cho mỗi đoạn tài liệu (1-10)', + instructionsLabel: 'Chỉ dẫn tạo câu hỏi', + instructionsDescription: 'Quy định đối tượng, ngữ cảnh và văn phong; hệ thống sẽ duy trì định dạng đầu ra chuẩn', + instructionsPlaceholder: 'Ví dụ: tạo câu hỏi hỗ trợ khách hàng tự nhiên, tránh lối hành văn dạng đề thi…' + }, + profile: { + label: 'Tự động tạo mô tả kho tri thức', + description: 'Tự động cập nhật mô tả kho tri thức từ bản tóm tắt các tài liệu khi thêm, xóa hoặc cập nhật tài liệu. Quá trình tổng hợp không gọi mô hình; chỉ chạy một yêu cầu nhỏ khi có thay đổi nội dung.', + modelLabel: 'Mô hình tạo mô tả', + modelDescription: 'Để trống để dùng lại mô hình tóm tắt của kho tri thức.', + modelPlaceholder: 'Chọn mô hình tạo mô tả', + instructionsLabel: 'Chỉ dẫn mô tả', + instructionsDescription: 'Xác định đối tượng, thuật ngữ cần giữ lại hoặc văn phong; định dạng đầu ra được giữ cố định.', + instructionsPlaceholder: 'Ví dụ: Viết cho nhân viên hỗ trợ; mô tả sản phẩm bằng từ ngữ dễ hiểu và giữ nguyên mã sản phẩm…' + }, + autoTag: { + label: 'Tự động gắn thẻ', + description: 'Sau khi xử lý tài liệu, tự động chọn thẻ phù hợp từ danh sách thẻ sẵn có của kho tri thức. Thẻ sẽ không tự sinh mới hay bị xóa, nhưng phát sinh thêm một lượt gọi mô hình.', + modelLabel: 'Mô hình phân loại', + modelDescription: 'Để trống để dùng lại mô hình tóm tắt của kho tri thức.', + modelPlaceholder: 'Chọn mô hình phân loại', + maxTagsLabel: 'Số thẻ tối đa mỗi tài liệu', + maxTagsDescription: 'Tự động liên kết 1-10 thẻ sẵn có cho mỗi tài liệu.', + skipIfTaggedLabel: 'Bỏ qua tài liệu đã có thẻ', + skipIfTaggedDescription: 'Khi bật, các tài liệu đã được gắn thẻ thủ công khi tải lên sẽ được giữ nguyên, tránh làm thay đổi phân loại đã định.' + }, + tableMetadataInstructions: { + label: 'Chỉ dẫn siêu dữ liệu bảng', + description: 'Bổ sung ngữ cảnh nghiệp vụ và ngữ nghĩa cột vào bản tóm tắt CSV/Excel để tối ưu truy xuất', + placeholder: 'Ví dụ: đây là bảng đơn bán hàng, số tiền tính bằng CNY, trạng thái dùng mã nội bộ…' + } + }, + multimodal: { + title: 'Cấu hình xử lý hình ảnh', + description: 'Cấu hình nhận diện nội dung hình ảnh để phân tích và truy xuất dữ liệu phi văn bản' + }, + asr: { + title: 'Nhận dạng giọng nói (ASR)', + description: 'Cấu hình ASR (chuyển giọng nói thành văn bản). Cho phép tải lên tệp âm thanh (mp3, wav, m4a, flac, ogg) để bóc băng nội dung. Không hỗ trợ tệp video.', + label: 'Bật nhận dạng giọng nói', + desc: 'Khi bật, có thể tải tệp âm thanh vào kho tri thức; nội dung giọng nói sẽ được chuyển thành văn bản để xử lý và truy xuất.', + modelLabel: 'Mô hình ASR', + modelDescription: 'Mô hình chuyển giọng nói thành văn bản (ví dụ: OpenAI Whisper)', + modelPlaceholder: 'Chọn mô hình ASR', + languageLabel: 'Gợi ý ngôn ngữ âm thanh', + languageDescription: 'Không bắt buộc. Gợi ý ngôn ngữ chính giúp tăng độ chính xác của mô hình ASR; để trống để tự động phát hiện.', + languagePlaceholder: 'Ví dụ: zh hoặc en; để trống để tự động phát hiện' + } + }, + chat: { + channelWeb: 'Web', + channelApi: 'API', + channelIm: 'IM', + chunkLabel: 'Chunk {index}:', + navigateToDocument: 'Xem chi tiết tài liệu', + chunkIdLabel: 'ID Chunk:', + documentIdLabel: 'ID tài liệu:', + faqIdLabel: 'ID FAQ:', + faqContainerIdLabel: 'ID container:', + faqAnswersLabel: 'Câu trả lời:', + chunkOrdinal: 'Chunk {index}', + previewContent: 'Xem trước nội dung', + noPlanSteps: 'Không có các bước chi tiết', + chunkIndexLabel: 'Chunk #{index}', + chunkPositionLabel: '(Vị trí: {position})', + noRelatedChunks: 'Không tìm thấy Chunk liên quan', + noSearchResults: 'Không tìm thấy kết quả', + relevanceHigh: 'Độ liên quan cao', + relevanceMedium: 'Độ liên quan trung bình', + relevanceLow: 'Độ liên quan thấp', + relevanceWeak: 'Độ liên quan yếu', + webSearchNoResults: 'Không tìm thấy kết quả tìm kiếm web', + otherSource: 'Nguồn khác', + webGroupIntro: '{count} mục sau đến từ', + graphConfigTitle: 'Cấu hình đồ thị', + entityTypesLabel: 'Loại thực thể:', + relationTypesLabel: 'Loại quan hệ:', + graphResultsHeader: 'Tìm thấy {count} kết quả liên quan', + graphNoResults: 'Không tìm thấy thông tin đồ thị liên quan', + unknownLink: 'Liên kết không xác định', + contentLengthLabel: 'Độ dài {value}', + notProvided: 'Chưa cung cấp', + promptLabel: 'Prompt', + errorMessageLabel: 'Thông báo lỗi', + summaryLabel: 'Tóm tắt', + rawTextLabel: 'Văn bản thô', + collapseRaw: 'Thu gọn bản gốc', + expandRaw: 'Mở rộng bản gốc', + noWebContent: 'Không tải được nội dung web', + webFetchStatusSuccess: 'Đã tải', + webFetchStatusFailed: 'Thất bại', + webFetchStatusSkipped: 'Đã bỏ qua', + webFetchErrorCode: 'Mã lỗi', + webFetchRetryable: 'Có thể thử lại', + webFetchContentRange: 'Ký tự {start}–{end} trên {total}', + webFetchPartialContent: 'Một phần trang', + webFetchSummaryFailed: 'Tóm tắt thất bại', + lengthChars: '{value} ký tự', + lengthThousands: '{value}k ký tự', + lengthTenThousands: '{value} vạn ký tự', + noDatabaseRecords: 'Không tìm thấy bản ghi phù hợp', + nullValuePlaceholder: '', + chunkCountValue: '{count} Chunk', + documentDescriptionLabel: 'Mô tả:', + documentSourceLabel: 'Nguồn:', + documentFileLabel: 'Tệp:', + documentMetadataLabel: 'Metadata', + documentInfoEmpty: 'Không có thông tin tài liệu', + positionLabel: 'Vị trí:', + chunkPositionValue: 'Chunk #{index}', + contentLengthLabelSimple: 'Độ dài nội dung:', + fullContentLabel: 'Toàn bộ nội dung', + copyContent: 'Sao chép nội dung', + knowledgeBaseCount: '{count} kho tri thức', + noKnowledgeBases: 'Không có kho tri thức nào', + enterDescription: 'Nhập mô tả', + rawOutputLabel: 'Kết quả thô', + wikiWritePageTitle: 'Ghi trang Wiki', + wikiReplaceTextTitle: 'Thay thế văn bản Wiki', + wikiRenamePageTitle: 'Đổi tên trang Wiki', + wikiDeletePageTitle: 'Xóa trang Wiki', + wikiActionCreated: 'Đã tạo', + wikiActionUpdated: 'Đã cập nhật', + wikiActionRenamed: 'Đã đổi tên', + wikiActionDeleted: 'Đã xóa', + wikiFieldSlug: 'Slug', + wikiFieldTitle: 'Tiêu đề', + wikiFieldPageType: 'Loại trang', + wikiFieldSummary: 'Tóm tắt', + wikiFieldOldText: 'Văn bản cũ', + wikiFieldNewText: 'Văn bản mới', + wikiFieldOldSlug: 'Slug cũ', + wikiFieldNewSlug: 'Slug mới', + wikiFieldAffectedPages: 'Trang bị ảnh hưởng', + wikiAffectedCount: 'Đã cập nhật {count} liên kết trang', + processError: 'Lỗi xử lý', + sessionExcerpt: 'Trích đoạn phiên', + noAnswerContent: '(Không có nội dung trả lời)', + manualSourcesHeading: 'Nguồn tham khảo', + noMatchFound: 'Không tìm thấy nội dung phù hợp', + deleteSessionFailed: 'Xóa thất bại, vui lòng thử lại sau!', + imageTooMany: 'Tối đa 5 hình ảnh', + imageTypeSizeError: 'Chỉ hỗ trợ JPG/PNG/GIF/WEBP dung lượng dưới 10MB', + imageUploadTooltip: 'Tải ảnh lên (hỗ trợ dán/kéo thả)', + attachmentUploadTooltip: 'Tải tệp đính kèm (tài liệu, âm thanh,...)', + attachmentWithCount: 'Đã tải lên {count} tệp đính kèm', + attachmentTooMany: 'Tối đa {max} tệp đính kèm', + attachmentTotalTooMany: 'Tổng số ảnh và tệp đính kèm không được vượt quá {max}', + attachmentTooLarge: 'Tệp {name} vượt quá giới hạn {max}MB', + attachmentTypeNotSupported: 'Định dạng tệp không được hỗ trợ: {name}', + attachmentUploading: 'Đang tải lên {progress}%', + attachmentParsing: 'Đang xử lý', + attachmentReady: 'Sẵn sàng', + attachmentUploadFailed: 'Tải tệp đính kèm thất bại', + attachmentParseFailed: 'Phân tích tệp đính kèm thất bại', + attachmentStillProcessing: 'Tệp đính kèm {name} vẫn đang được xử lý', + memoryUsedCount: 'Đã dùng {count} ký ức', + memoryForget: 'Xoá ký ức này', + memoryForgotten: 'Đã xoá ký ức', + memoryForgetFailed: 'Xoá thất bại', + memoryHint: 'Đây là các ký ức dài hạn được dùng cho câu trả lời này. Khi xoá, ký ức sẽ không được tiếp tục sử dụng.', + suggestedQuestions: 'Gợi ý câu hỏi', + followUpQuestions: 'Hỏi tiếp', + followUpQuestionsLoading: 'Đang tải câu hỏi gợi ý', + refreshSuggestedQuestions: 'Xem thêm', + thinking: 'Đang suy luận...', + thinkingAlt: 'Đang suy luận', + conversationTime: { + today: 'Hôm nay lúc {time}', + yesterday: 'Hôm qua lúc {time}', + thisYear: '{month}/{day} lúc {time}', + otherYear: '{month}/{day}/{year} lúc {time}' + }, + preparingAnswer: 'Đang chuẩn bị câu trả lời…', + connectingModelAndGeneratingAnswer: 'Đang kết nối mô hình và tạo câu trả lời…', + modelStillResponding: 'Mô hình phản hồi lâu hơn bình thường, vui lòng đợi…', + deepThoughtCompleted: 'Đã hoàn tất suy luận sâu', + deepThoughtAlt: 'Suy luận sâu hoàn tất', + referencesTitle: 'Đã tham chiếu {count} mục liên quan', + referencesDocCount: 'Đã tham chiếu {count} tài liệu', + referencesWebCount: 'Đã tham chiếu {count} kết quả web', + referencesDocAndWebCount: 'Đã tham chiếu {docCount} tài liệu và {webCount} trang web', + referencesDrawerTitle: 'Nguồn trích dẫn', + referencesDrawerTitleWeb: 'Nguồn web', + referencesDrawerTitleDocs: 'Nguồn tài liệu', + referencesDrawerTitleTools: 'Kết quả công cụ', + referencesDrawerTitleMixed: 'Nguồn trích dẫn', + referencesDrawerWebSection: 'Web', + referencesDrawerDocsSection: 'Tài liệu', + referencesDrawerToolsSection: 'Công cụ', + referencesDrawerEmpty: 'Không có nguồn trích dẫn', + sandbox: { + panelTitle: 'Sandbox', + tabArtifacts: 'Artifacts', + tabTerminal: 'Terminal', + tabDesktop: 'Desktop', + artifactsEmpty: 'Chưa có tệp nào được tạo trong cuộc trò chuyện này.', + artifactScope: 'Phạm vi tệp', + artifactsCurrent: 'Lượt này', + artifactsAll: 'Tất cả tệp', + artifactsSearch: 'Tìm theo tên tệp', + artifactsNoMatches: 'Không tìm thấy tệp phù hợp', + desktopNotStarted: 'Chưa kết nối desktop. Kết nối để truy cập Sandbox của cuộc trò chuyện này.', + desktopStart: 'Kết nối desktop', + desktopStarting: 'Đang kết nối desktop… (lần đầu mất khoảng 3-8 giây)', + desktopUnsupported: 'Cấu hình Sandbox này không hỗ trợ desktop. Hãy chọn mẫu image có desktop trong cài đặt Sandbox không gian làm việc, sử dụng bộ lưu trữ Cube hoặc E2B.', + desktopBusy: 'Cuộc trò chuyện này đang có desktop mở. Mỗi thời điểm chỉ cho phép một kết nối.', + desktopStartFailed: 'Khởi động desktop thất bại. Vui lòng thử lại.', + desktopRebuilt: 'Sandbox đã được dựng lại để cập nhật kỹ năng; desktop trước đó và các thay đổi chưa lưu đã bị xoá. Kết nối lại để mở desktop mới.', + desktopNeedsProvision: 'Cuộc trò chuyện này chưa có Sandbox đang chạy. Tạo và kết nối sẽ khởi chạy Sandbox mới, tính phí theo cấu hình không gian làm việc.', + desktopCreateAndStart: 'Tạo và kết nối', + desktopPaused: 'Sandbox của cuộc trò chuyện đang tạm dừng. Kết nối desktop sẽ tiếp tục chạy lại.', + desktopDisconnected: 'Đã ngắt kết nối desktop', + desktopIdleDisconnected: 'Desktop đã ngắt kết nối do không hoạt động. Sandbox sẽ tự tạm dừng theo thời gian chờ (TTL). Bạn có thể kết nối lại.', + desktopRetry: 'Kết nối lại', + notStarted: 'Terminal chưa chạy. Khởi động terminal để kết nối vào Sandbox của cuộc trò chuyện, tự động tạo mới hoặc tiếp tục nếu cần.', + paused: 'Sandbox của cuộc trò chuyện đang tạm dừng. Khởi động terminal sẽ tiếp tục chạy lại.', + start: 'Khởi động terminal', + connecting: 'Đang kết nối tới Sandbox…', + needsProvision: 'Cuộc trò chuyện này chưa có Sandbox đang chạy. Tạo mới sẽ khởi chạy Sandbox, tính phí theo cấu hình không gian làm việc.', + createAndStart: 'Tạo và khởi động', + noSandbox: 'Chưa có Sandbox và agent hiện tại chưa cấu hình bộ lưu trữ Sandbox. Hãy chuyển sang agent có cấu hình Sandbox hoặc gửi tin nhắn yêu cầu chạy mã.', + unsupported: 'Bộ lưu trữ Sandbox hiện tại không hỗ trợ terminal tương tác', + disconnected: 'Mất kết nối', + retry: 'Kết nối lại', + sessionEnded: 'Phiên terminal đã kết thúc', + idleDisconnected: 'Terminal đã ngắt kết nối do không hoạt động. Sandbox sẽ tự tạm dừng theo thời gian chờ (TTL). Bạn có thể kết nối lại.', + authRevoked: 'Phiên làm việc hết hiệu lực nên terminal đã bị ngắt kết nối. Vui lòng đăng nhập lại rồi kết nối lại.' + }, + questionMinimapTitle: 'Hỏi đáp', + questionMinimapPosition: 'Lượt {current}/{total}', + questionMinimapAriaLabel: 'Danh sách câu hỏi', + questionMinimapAttachmentPlaceholder: '(Tệp đính kèm)', + referenceChunkCount: '{count} Chunk', + fallbackHint: 'Không tìm thấy nội dung liên quan trong kho tri thức. Dưới đây là phản hồi trực tiếp từ mô hình.', + truncatedHint: 'Câu trả lời đã bị cắt do đạt giới hạn độ dài phản hồi. Dưới đây là nội dung mô hình đã tạo trước khi dừng.', + rewind: { + tooltip: 'Quay lại đây', + confirmBody: 'Các tin nhắn sau đó sẽ bị xoá. Quay lại từ một câu hỏi cũng sẽ xoá câu hỏi đó và đưa nội dung về ô nhập. Không gian làm việc sẽ hoàn tác nếu có điểm kiểm tra. Thao tác này không thể phục hồi.', + confirmButton: 'Quay lại', + cancelButton: 'Huỷ', + success: 'Đã quay lại', + busy: 'Vui lòng đợi lượt này hoàn tất trước khi quay lại', + noCheckpoint: 'Không thể quay lại: phiên này có không gian làm việc đang hoạt động nhưng không có điểm kiểm tra khả dụng', + sandboxReplaced: 'Không thể quay lại: Sandbox đã bị thay thế, không thể truy cập điểm kiểm tra cũ', + reloadFailed: 'Đã quay lại cuộc trò chuyện nhưng không thể tải lại lịch sử. Vui lòng làm mới trang nếu thiếu tin nhắn cũ', + failed: 'Quay lại thất bại. Vui lòng thử lại', + skipped: 'Đã quay lại cuộc trò chuyện; không gian làm việc được giữ nguyên', + skipNoSandbox: 'Đã quay lại cuộc trò chuyện; không gian làm việc được giữ nguyên (không có Sandbox liên kết)', + skipNoCheckpoint: 'Đã quay lại cuộc trò chuyện; không gian làm việc được giữ nguyên (không có điểm kiểm tra để khôi phục)' + }, + requestInfoTitle: 'Thông tin yêu cầu', + requestInfoRequestId: 'ID yêu cầu', + requestInfoMessageId: 'ID tin nhắn', + requestInfoSessionId: 'ID phiên', + requestInfoUrl: 'Yêu cầu', + requestInfoSentAt: 'Gửi lúc', + requestInfoEmpty: 'Không có thông tin yêu cầu', + referenceSourceBack: 'Tất cả nguồn dẫn', + referenceSourceView: 'Xem trong tài liệu gốc', + referenceSourceRelocate: 'Định vị lại', + referenceSourceLocating: 'Đang định vị đoạn trích dẫn…', + referenceSourceExact: 'Đã định vị đoạn trích dẫn gốc', + referenceSourcePartial: 'Đã đánh dấu đoạn trích nguồn đã xác thực; một phần trích dẫn chưa khớp', + referenceSourceBlock: 'Đã định vị vùng nguồn; chưa xác nhận văn bản chính xác', + referenceSourceAmbiguous: 'Nhiều đoạn trích khớp nhau; vị trí có thể không duy nhất', + referenceSourceStale: 'Nguồn hoặc nội dung đã thay đổi; không thể định vị chính xác trích dẫn này', + referenceSourcePrevious: 'Vị trí trích dẫn trước', + referenceSourceNext: 'Vị trí trích dẫn tiếp theo', + referenceSourceFoundPage: 'Tìm thấy tại trang {page}', + referenceSourceNotFound: 'Không thể định vị chính xác đoạn trích dẫn; tài liệu gốc đang mở', + referenceSourceOpenWeb: 'Mở trang web tại đoạn trích dẫn này' + }, + tenant: { + title: 'Thông tin không gian làm việc', + currentTenant: 'Không gian làm việc hiện tại', + switchTenant: 'Chuyển không gian làm việc', + switcher: { + menuLabel: 'Chuyển không gian làm việc', + currentBadge: 'Hiện tại', + homeTooltip: 'Không gian làm việc chính', + empty: 'Bạn chỉ thuộc về một không gian làm việc' + }, + sectionDescription: 'Xem cấu hình chi tiết của không gian làm việc', + statusActive: 'Đang hoạt động', + statusInactive: 'Chưa kích hoạt', + statusSuspended: 'Bị tạm ngưng', + statusUnknown: 'Không xác định', + loadingInfo: 'Đang tải thông tin...', + retry: 'Thử lại', + unknown: 'Không xác định', + formatError: 'Lỗi định dạng', + searchPlaceholder: 'Tìm theo tên hoặc nhập ID không gian làm việc...', + noMatch: 'Không tìm thấy không gian làm việc phù hợp', + switchSuccessTitle: 'Đã chuyển không gian làm việc', + switchSuccessContent: 'Bạn đang ở {name}', + loadTenantsFailed: 'Không thể tải danh sách không gian làm việc', + loading: 'Đang tải...', + loadMore: 'Tải thêm', + create: { + action: 'Tạo không gian làm việc mới', + dialogTitle: 'Tạo không gian làm việc mới', + dialogSubtitle: 'Mỗi không gian làm việc có kho tri thức và thành viên riêng. Bạn sẽ là chủ sở hữu của không gian mới.', + nameLabel: 'Tên không gian làm việc', + namePlaceholder: 'Ví dụ: Dự án mới', + nameRequired: 'Vui lòng nhập tên không gian làm việc', + descriptionLabel: 'Mô tả (tuỳ chọn)', + descriptionPlaceholder: 'Mô tả ngắn gọn mục đích của không gian làm việc này', + submit: 'Tạo', + cancel: 'Huỷ', + success: 'Đã tạo không gian làm việc thành công', + failed: 'Tạo không gian làm việc thất bại', + disabled: 'Hệ thống chỉ cho phép tham gia qua lời mời. Bạn không thể tự tạo không gian làm việc.' + }, + details: { + idLabel: 'ID không gian làm việc', + idDescription: 'Mã định danh duy nhất của không gian làm việc', + nameLabel: 'Tên không gian làm việc', + nameDescription: 'Tên không gian làm việc của bạn', + descriptionLabel: 'Mô tả không gian làm việc', + descriptionDescription: 'Mô tả chi tiết về không gian làm việc', + businessLabel: 'Lĩnh vực hoạt động', + businessDescription: 'Lĩnh vực chuyên môn của không gian làm việc', + statusLabel: 'Trạng thái', + statusDescription: 'Trạng thái hoạt động hiện tại của không gian làm việc', + createdAtLabel: 'Thời gian tạo', + createdAtDescription: 'Thời điểm không gian làm việc được tạo', + editName: 'Đổi tên', + editNamePlaceholder: 'Nhập tên không gian làm việc mới', + editNameConfirm: 'Lưu', + editNameCancel: 'Huỷ', + editNameRequired: 'Tên không gian làm việc không được để trống', + editNameSuccess: 'Đã cập nhật tên không gian làm việc', + editNameFailed: 'Cập nhật tên không gian làm việc thất bại', + editDescription: 'Sửa mô tả', + editDescriptionPlaceholder: 'Nhập mô tả mới', + editDescriptionSuccess: 'Đã cập nhật mô tả', + editDescriptionFailed: 'Cập nhật mô tả thất bại', + descriptionEmptyPlaceholder: 'Chưa thiết lập' + }, + storage: { + quotaLabel: 'Hạn mức lưu trữ', + quotaDescription: 'Tổng dung lượng lưu trữ được cấp cho không gian làm việc', + usedLabel: 'Đã sử dụng', + usedDescription: 'Dung lượng bộ lưu trữ đã dùng', + usageLabel: 'Mức sử dụng', + usageDescription: 'Tỷ lệ phần trăm dung lượng lưu trữ đã dùng' + }, + leaveDangerZone: { + title: 'Rời khỏi không gian làm việc này', + desc: 'Chấm dứt tư cách thành viên của bạn. Bạn sẽ mất quyền truy cập vào kho tri thức và AI Agent tại đây. Bạn có thể được mời lại sau.', + button: 'Rời không gian làm việc' + }, + deleteDangerZone: { + title: 'Xoá không gian làm việc này', + desc: 'Xoá toàn bộ không gian làm việc và cấu hình. Thành viên sẽ không thể truy cập vào kho tri thức, AI Agent hoặc API key nữa.', + button: 'Xoá không gian làm việc', + confirmTitle: 'Xoá không gian làm việc này?', + confirmBody: 'Thao tác này sẽ xoá "{name}" và vô hiệu hoá toàn bộ kho tri thức, AI Agent, thành viên cùng API key liên quan. Hành động này không thể hoàn tác.', + confirmHint: 'Nhập tên không gian làm việc "{name}" để xác nhận xoá.', + confirm: 'Xoá không gian làm việc', + nameMismatch: 'Tên không gian làm việc không khớp', + success: 'Đã xoá không gian làm việc', + failed: 'Xoá không gian làm việc thất bại' + }, + messages: { + fetchFailed: 'Không thể tải thông tin không gian làm việc', + networkError: 'Lỗi kết nối mạng, vui lòng thử lại sau' + }, + api: { + title: 'Thông tin API', + docLabel: 'Tài liệu API', + docDescription: 'Xem tài liệu API đầy đủ và các ví dụ', + openDoc: 'Mở tài liệu', + userIdLabel: 'ID người dùng', + userIdDescription: 'Mã định danh duy nhất của bạn', + usernameLabel: 'Tên người dùng', + usernameDescription: 'Tên đăng nhập của bạn', + emailLabel: 'Email', + emailDescription: 'Địa chỉ email đã đăng ký', + createdAtLabel: 'Thời gian đăng ký', + createdAtDescription: 'Thời điểm tài khoản được tạo', + desktopPortLabel: 'Cổng API cục bộ (desktop)', + desktopPortDescription: 'Dùng cổng cố định (vd: 37841) để các công cụ như tiện ích Chrome duy trì URL API. Đặt 0 để chọn cổng ngẫu nhiên mỗi lần khởi chạy. Khởi động lại ứng dụng sau khi lưu.', + desktopPortSave: 'Lưu', + desktopPortSaved: 'Đã lưu. Hãy khởi động lại ứng dụng để áp dụng thay đổi.', + desktopPortSaveFailed: 'Lưu thất bại', + desktopPortInvalid: 'Vui lòng nhập cổng từ 0 đến 65535', + desktopBindPublicLabel: 'Cho phép truy cập API qua mạng cục bộ (LAN)', + desktopBindPublicDescription: 'Khi bật, máy chủ nhúng sẽ lắng nghe trên 0.0.0.0 để các thiết bị khác trong mạng LAN có thể kết nối API qua địa chỉ bên dưới. Tùy chọn này làm tăng phạm vi phơi nhiễm mạng—cần dùng tường lửa máy chủ và cấu hình định tuyến phù hợp. Khởi động lại ứng dụng sau khi đổi.', + desktopBindPublicSaved: 'Đã lưu. Hãy khởi động lại ứng dụng để áp dụng thay đổi.', + desktopBindPublicSaveFailed: 'Lưu thất bại', + lanUrlLabel: 'URL cơ sở API mạng LAN', + lanUrlDescription: 'Hiển thị sau khi bật “Cho phép truy cập qua LAN” và khởi động lại ứng dụng. Nếu IP không đúng, hãy thay thế máy chủ lưu trữ bằng IPv4 của thiết bị từ cài đặt mạng hệ thống.', + lanUrlCopyTitle: 'Sao chép URL API mạng LAN', + lanUrlUnavailable: 'API đang lắng nghe trên mọi giao diện mạng, nhưng không tìm thấy IPv4 mạng LAN tự động. Vui lòng kiểm tra IPv4 trong cài đặt mạng và tạo thủ công địa chỉ http://IP_CỦA_BẠN:CỔNG/api/v1.' + } + }, + system: { + title: 'Thông tin hệ thống', + sectionDescription: 'Xem thông tin phiên bản hệ thống và cấu hình tài khoản người dùng', + loadingInfo: 'Đang tải thông tin...', + retry: 'Thử lại', + versionLabel: 'Phiên bản ứng dụng', + versionDescription: 'Phiên bản dịch vụ ứng dụng (weknora-app)', + frontendVersionLabel: 'Phiên bản giao diện', + frontendVersionDescription: 'Bản dựng giao diện người dùng (weknora-ui)', + versionMismatch: 'Không khớp với phiên bản ứng dụng', + buildTimeLabel: 'Thời gian dựng', + buildTimeDescription: 'Thời điểm hệ thống được dựng', + goVersionLabel: 'Phiên bản Go', + goVersionDescription: 'Phiên bản ngôn ngữ Go backend đang dùng', + startedAtLabel: 'Thời điểm khởi động dịch vụ', + startedAtDescription: 'Thời gian tiến trình backend hiện tại bắt đầu hoạt động lần gần nhất', + uptimeLabel: 'Thời gian hoạt động', + uptimeDescription: 'Thời gian dịch vụ đã chạy liên tục kể từ lần khởi động này', + uptimeDays: '{n} ngày', + uptimeHours: '{n} giờ', + uptimeMinutes: '{n} phút', + uptimeSeconds: '{n} giây', + dbVersionLabel: 'Phiên bản cơ sở dữ liệu', + dbVersionDescription: 'Phiên bản migration cơ sở dữ liệu hiện tại', + dbMigrationFailedTag: 'Migration thất bại', + dbMigrationFailedTitle: 'Migration cơ sở dữ liệu thất bại', + dbMigrationFailedDesc: 'Quá trình migration cơ sở dữ liệu khi khởi động chưa hoàn tất. Một số bảng hoặc chỉ mục có thể bị thiếu, gây lỗi thu nạp Wiki, đồ thị tri thức và các tính năng khác. Vui lòng xem hướng dẫn khắc phục sự cố bên dưới; nếu lỗi tiếp diễn, hãy báo cáo sự cố qua liên kết.', + dbMigrationViewDocs: 'Xem hướng dẫn khắc phục sự cố', + dbMigrationReportIssue: 'Không giải quyết được? Báo cáo sự cố', + keywordIndexEngineLabel: 'Công cụ chỉ mục từ khóa', + keywordIndexEngineDescription: 'Công cụ chỉ mục từ khóa đang được sử dụng', + vectorStoreEngineLabel: 'Công cụ lưu trữ vector', + vectorStoreEngineDescription: 'Công cụ lưu trữ vector đang được sử dụng', + graphDatabaseEngineLabel: 'Công cụ cơ sở dữ liệu đồ thị', + graphDatabaseEngineDescription: 'Công cụ cơ sở dữ liệu đồ thị đang được sử dụng', + unknown: 'Không xác định', + messages: { + fetchFailed: 'Không thể lấy thông tin hệ thống', + networkError: 'Lỗi mạng, vui lòng thử lại sau' + }, + globalSettings: { + title: 'Cài đặt hệ thống', + description: 'Cấu hình runtime toàn nền tảng. Các thay đổi có hiệu lực ngay cho mọi không gian làm việc. Chỉ quản trị viên hệ thống mới có thể xem và chỉnh sửa.', + loading: 'Đang tải...', + empty: 'Không có cài đặt hệ thống nào khả dụng', + saving: 'Đang lưu', + saved: 'Đã lưu', + saveAnnouncement: 'Đã lưu {label}', + badgeRequiresRestart: 'Cần khởi động lại', + badgeSecret: 'Bảo mật', + badgeHighRisk: 'Rủi ro cao', + badgeOverride: 'Đã ghi đè', + badgeOverrideTooltip: 'Giá trị này đã được quản trị viên lưu vào cơ sở dữ liệu, ghi đè biến môi trường và giá trị mặc định tích hợp.', + modifiedAt: 'Sửa đổi lần cuối: {value}', + tagInputPlaceholder: 'Nhấn Enter để thêm mục, vd: example.com / *.foo.com / 10.0.0.0/8', + priorityHint: { + disclosure: 'Nguồn cấu hình và mức độ ưu tiên', + tier1: 'Các mục được lưu tại trang này (gắn thẻ "Đã ghi đè") luôn được ưu tiên cao nhất — biến môi trường của chúng sẽ bị bỏ qua.', + tier2: 'Các mục chưa lưu tại đây sẽ dùng biến môi trường, hoặc dùng giá trị mặc định tích hợp nếu chưa đặt biến môi trường.', + tier3: 'Để chuyển một mục về quyền kiểm soát của biến môi trường, hãy bấm nút "Đặt lại" ở hàng tương ứng.' + }, + sections: { + access: { + tab: 'Tài khoản & truy cập {count}', + title: 'Tài khoản & truy cập', + description: 'Quản lý quản trị viên hệ thống, đăng ký công khai và quy tắc tạo không gian làm việc.' + }, + tenant: { + tab: 'Mặc định không gian làm việc {count}', + title: 'Mặc định không gian làm việc', + description: 'Thiết lập hạn mức ban đầu và hành vi tương thích cho các không gian làm việc mới mà không làm thay đổi các không gian làm việc hiện có.' + }, + runtime: { + tab: 'Runtime & đồng thời {count}', + title: 'Runtime & đồng thời', + description: 'Cấu hình năng lực đồng thời cho các nhóm worker chạy nền và dịch vụ mô hình.', + restartHint: 'Cài đặt worker yêu cầu khởi động lại' + }, + security: { + tab: 'Bảo mật mạng {count}', + title: 'Bảo mật mạng', + description: 'Quản lý danh sách cho phép SSRF và quyền sử dụng Docker sandbox (docker.sock cục bộ tương đương với quyền root trên máy chủ).' + }, + other: { + tab: 'Khác {count}', + title: 'Cài đặt khác', + description: 'Các cài đặt trong bản triển khai này không thuộc nhóm tính năng tiêu chuẩn.' + } + }, + runtimeTable: { + setting: 'Cài đặt và mục đích', + value: 'Giá trị hiện tại' + }, + runtime: { + title: 'Runtime hàng đợi tác vụ', + description: 'Tải hàng đợi nền theo thời gian thực và năng lực xử lý theo tiến trình cho từng nhóm worker tách biệt. Bao gồm chi tiết tác vụ và điều khiển an toàn; tự động làm mới mỗi 5 giây.', + refresh: 'Làm mới', + autoRefresh: 'Tự động làm mới (mỗi 5 giây)', + loading: 'Đang tải...', + retry: 'Thử lại', + unavailableTitle: 'Hàng đợi tác vụ không khả dụng', + unavailable: 'Bản triển khai này không có hàng đợi Redis / asynq (chế độ Lite) — không có dữ liệu hiển thị.', + empty: 'Không có dữ liệu hàng đợi', + detailsTitle: 'Chi tiết hàng đợi', + detailsDescription: 'Tải trực tiếp và thời gian chờ cho từng luồng xử lý. “Thất bại (đã dừng)” nghĩa là tác vụ đã vượt quá giới hạn thử lại và sẽ không tự động chạy lại.', + poolsTitle: 'Nhóm worker', + poolsDescription: 'Mỗi giai đoạn đều có năng lực đảm bảo; giai đoạn cốt lõi và làm giàu dữ liệu có thể mượn thêm từ nhóm co giãn dùng chung.', + perInstance: 'Giá trị trên thẻ là hoạt động/năng lực của cụm', + poolConfigured: 'Mỗi tiến trình {value}', + poolInstances: '{value} instance', + poolUtilization: 'Đã dùng {value}%', + queueCount: '{value} hàng đợi', + weightShort: 'Trọng số {value}', + footnote: 'Giá trị trên thẻ hiển thị dung lượng hoạt động thực tế của cụm; cấu hình theo tiến trình yêu cầu khởi động lại. Nhóm tài nguyên dùng chung chỉ xử lý hàng đợi cốt lõi và làm giàu dữ liệu.', + updatedAt: 'Cập nhật lúc {value}', + errors: { + generic: 'Không thể tải thống kê hàng đợi' + }, + summary: { + title: 'Tổng quan runtime', + active: 'Đang chạy', + pending: 'Đang chờ', + retry: 'Đang thử lại', + archived: 'Thất bại (đã dừng)' + }, + columns: { + queue: 'Hàng đợi', + active: 'Đang chạy', + pending: 'Đang chờ', + scheduled: 'Đã lên lịch', + retry: 'Thử lại', + archived: 'Thất bại', + completed: 'Đã hoàn thành', + latency: 'Chờ lâu nhất', + status: 'Trạng thái' + }, + status: { + working: 'Đang xử lý', + waiting: 'Đang chờ', + idle: 'Nghỉ', + actionRequired: 'Cần xử lý', + retrying: 'Đang thử lại', + paused: 'Đã tạm dừng' + }, + failedNotice: { + title: '{count} tác vụ thất bại cần xử lý', + description: 'Chọn số lượng Thất bại (đỏ) trong bảng dưới đây để kiểm tra nguyên nhân, sau đó thử lại sau khi khắc phục lỗi gốc.' + }, + tasks: { + title: 'Chi tiết tác vụ · {queue}', + description: 'Kiểm tra trạng thái từng tác vụ. Tác vụ đã lên lịch và thử lại hiển thị lần chạy tiếp theo trước; các trạng thái khác hiển thị tác vụ mới nhất trước.', + listTitle: 'Tác vụ {state}', + openAria: 'Xem {count} tác vụ {state} trong {queue}', + unavailable: 'Chi tiết tác vụ không khả dụng trên bản triển khai này', + empty: 'Hàng đợi này không có tác vụ {state}', + loadError: 'Không thể tải chi tiết tác vụ', + loadMore: 'Tải thêm', + loadedSummary: 'Đã tải {count} — cuộn hoặc nhấn để tải thêm', + loadedAll: 'Đã tải toàn bộ {count}', + loadingMore: 'Đang tải thêm…', + attempts: 'Lần thử {current}/{max}', + unknownTarget: 'Không xác định được đối tượng liên quan', + knowledgeBaseLabel: 'ID Kho tri thức', + knowledgeLabel: 'ID Tài liệu', + taskIDLabel: 'ID Tác vụ nghiệp vụ', + tenantLabel: 'ID Không gian làm việc', + sourceLabel: 'ID Nguồn', + targetLabel: 'ID Đích', + sourceKBLabel: 'Kho tri thức nguồn', + targetKBLabel: 'Kho tri thức đích', + dataSourceLabel: 'ID Nguồn dữ liệu', + syncLogLabel: 'ID Nhật ký đồng bộ', + knowledgeCountLabel: 'Số tài liệu', + enqueuedAt: 'Đã vào hàng đợi', + startedAt: 'Đã bắt đầu', + nextProcessAt: 'Lần chạy tiếp theo', + lastFailedAt: 'Thất bại gần nhất', + completedAt: 'Đã hoàn thành', + deadline: 'Hạn chót', + worker: 'Worker', + health: 'Tình trạng runtime', + orphaned: 'Mất heartbeat worker; đang chờ phục hồi', + cancel: 'Hủy tác vụ', + cancelConfirm: 'Thao tác này sử dụng quy trình hủy nghiệp vụ và dừng các tác vụ liên quan đến tài liệu này. Tiếp tục hủy?', + runNow: 'Chạy ngay', + runNowConfirm: 'Tác vụ sẽ chuyển sang trạng thái đang chờ ngay mà không đặt lại số lần thử. Tiếp tục?', + deleteRecord: 'Xóa bản ghi', + deleteConfirm: 'Thao tác này chỉ xóa bản ghi khỏi hàng đợi hiện tại, không chạy hay hoàn tất tác vụ gốc và vẫn giữ nguyên nhật ký lịch sử. Tiếp tục xóa?', + purgeArchived: 'Xóa tất cả tác vụ thất bại', + purgeArchivedConfirm: 'Xóa đồng loạt toàn bộ {count} bản ghi thất bại khỏi hàng đợi này. Thao tác chỉ dọn dẹp các tác vụ thất bại trong hàng đợi — không ảnh hưởng đến tác vụ đang chạy hay đang chờ, và không khôi phục trạng thái nghiệp vụ của tài liệu đã thất bại. Tiếp tục xóa?', + purgeArchivedSuccess: 'Đã xóa {count} tác vụ thất bại', + purgeArchivedError: 'Không thể xóa các tác vụ thất bại', + stateFilter: 'Lọc theo trạng thái tác vụ', + states: { + active: 'Đang chạy', + pending: 'Đang chờ', + scheduled: 'Đã lên lịch', + retry: 'Đang thử lại', + archived: 'Thất bại', + completed: 'Đã hoàn thành' + }, + guides: { + active: 'Kiểm tra worker, thời gian bắt đầu, hạn chót và trạng thái mất kết nối (orphan). Nút hủy chỉ khả dụng khi có thể cập nhật trạng thái nghiệp vụ an toàn.', + pending: 'Tác vụ đang chờ chưa có worker tiếp nhận. Thao tác hủy sẽ cập nhật trạng thái nghiệp vụ thay vì chỉ xóa dữ liệu trên Redis.', + scheduled: 'Tác vụ đã lên lịch có thể chạy sớm hơn; các tác vụ pipeline tài liệu cũng hỗ trợ hủy nghiệp vụ an toàn.', + retry: 'Dựa vào lỗi gần nhất, số lần thử và thời gian chạy kế tiếp để quyết định chạy ngay hay hủy tác vụ.', + archived: 'Khắc phục lỗi gốc trước khi chạy lại. Việc xóa bản ghi không hoàn tất tác vụ nghiệp vụ gốc.', + completed: 'Chỉ hiển thị các tác vụ vừa hoàn thành còn lưu kết quả. Không hỗ trợ thao tác quản trị.' + }, + actionSuccess: { + cancel: 'Đã hủy tác vụ', + run_now: 'Đã chuyển tác vụ sang hàng chờ', + delete: 'Đã xóa bản ghi lỗi' + }, + actionError: { + cancel: 'Không thể hủy tác vụ', + run_now: 'Không thể chạy tác vụ', + delete: 'Không thể xóa bản ghi' + }, + taskTypes: { + documentProcess: 'Phân tích tài liệu', + manualProcess: 'Xử lý lại thủ công', + temporaryDocumentProcess: 'Phân tích tệp đính kèm chat', + postProcess: 'Hậu xử lý tài liệu', + summary: 'Tạo tóm tắt', + tableSummary: 'Tạo tóm tắt bảng biểu', + question: 'Tạo câu hỏi', + multimodal: 'Xử lý đa phương thức hình ảnh', + graph: 'Trích xuất đồ thị tri thức', + sync: 'Đồng bộ nguồn dữ liệu', + faqImport: 'Nhập FAQ', + batchReparse: 'Phân tích lại hàng loạt', + batchDelete: 'Xóa hàng loạt', + move: 'Di chuyển tài liệu', + indexDelete: 'Xóa chỉ mục', + kbClone: 'Nhân bản kho tri thức', + kbDelete: 'Xóa kho tri thức', + wikiIngest: 'Tạo nội dung Wiki', + wikiFinalize: 'Hoàn tất Wiki' + } + }, + models: { + title: 'Xử lý đồng thời mô hình', + description: 'Mức xử lý đồng thời thực tế của dịch vụ mô hình từ các tác vụ nền. Phần phía trên lập lịch tác vụ; phần này thể hiện giai đoạn điều tiết dịch vụ mô hình riêng biệt.', + scope: 'Đang hoạt động trên toàn cụm · Đang chờ ở cấp cục bộ', + disabled: 'Đã tắt điều phối mức đồng thời mô hình nền. Hãy cấu hình giới hạn đồng thời mặc định trong Cài đặt chung.', + empty: 'Chưa có hoạt động mô hình nào. Mô hình sẽ xuất hiện sau lượt gọi chạy nền đầu tiên.', + backgroundOnly: 'Chỉ áp dụng tác vụ nền; không bao gồm trò chuyện trực tiếp', + columns: { + model: 'ID mô hình', + active: 'Đang xử lý', + waiting: 'Bị điều tiết', + usage: 'Mức đồng thời' + }, + status: { + queued: 'Đang điều tiết', + full: 'Đạt giới hạn' + } + }, + pools: { + core: 'Phân tích cốt lõi', + postprocess: 'Điều phối hậu xử lý', + enrichment: 'Làm giàu dữ liệu', + maintenance: 'Bảo trì & đồng bộ', + shared: 'Dùng chung linh hoạt', + wiki: 'Hồ tác vụ Wiki' + }, + poolDescriptions: { + core: 'Đảm bảo tài nguyên phân tích tài liệu và thủ công', + postprocess: 'Hoàn tất phân tích và phân nhánh làm giàu dữ liệu', + enrichment: 'Tạo tóm tắt, hình ảnh, đồ thị và câu hỏi', + maintenance: 'Đồng bộ nguồn, xử lý hàng loạt và dọn dẹp dữ liệu xóa', + shared: 'Được mượn bởi tác vụ cốt lõi hoặc làm giàu dữ liệu tùy theo lượng tồn đọng', + wiki: 'Tạo nội dung Wiki và hoàn thiện toàn cục' + }, + queueNames: { + default: 'Phân tích tài liệu', + chat_attachment: 'Tệp đính kèm trò chuyện', + postprocess: 'Hậu xử lý', + summary: 'Tóm tắt', + sync: 'Đồng bộ nguồn', + low: 'Bảo trì & hàng loạt', + multimodal: 'Đa phương thức', + graph: 'Trích xuất đồ thị', + question: 'Câu hỏi', + wiki: 'Quy trình Wiki' + }, + queueDescriptions: { + default: 'Phân tích tài liệu, phân tích lại thủ công', + chat_attachment: 'Phân tích tệp tải lên theo phiên trò chuyện', + postprocess: 'Hoàn tất phân tích, phân nhánh làm giàu dữ liệu', + summary: 'Tóm tắt tài liệu & bảng biểu', + sync: 'Đồng bộ thủ công & định kỳ', + low: 'Nhập FAQ, phân tích lại hàng loạt, dọn dẹp', + multimodal: 'OCR hình ảnh, chú thích thị giác', + graph: 'Trích xuất đồ thị cấp Chunk', + question: 'Tạo câu hỏi cấp Chunk', + wiki: 'Tạo nội dung, hoàn thiện chỉ mục' + } + }, + audit: { + action: { + system: { + admin_promoted: 'Cấp quyền quản trị hệ thống', + api_key_created: 'Tạo API key nền tảng', + api_key_revoked: 'Thu hồi API key nền tảng', + admin_revoked: 'Thu hồi quyền quản trị hệ thống', + user_password_reset: 'Đặt lại mật khẩu người dùng', + user_created: 'Tạo người dùng mới', + queue_task_retried: 'Chạy lại tác vụ thất bại', + queue_task_deleted: 'Xóa bản ghi tác vụ thất bại', + queue_task_run_now: 'Chạy ngay tác vụ hàng đợi', + queue_task_cancelled: 'Hủy tác vụ hàng đợi', + queue_archived_purged: 'Dọn sạch tác vụ thất bại', + setting_changed: 'Thay đổi cài đặt hệ thống' + } + }, + outcome: { + success: 'Thành công', + denied: 'Bị từ chối' + }, + target: { + bulkQuota: 'Đồng bộ hàng loạt: hạn ngạch lưu trữ mặc định', + bulkQuotaDiff: 'Áp dụng cho {count} không gian làm việc ({gb} GB)', + promoteIdempotent: 'Đối tượng đã là quản trị viên hệ thống (idempotent)', + revokeNoop: 'Đối tượng không phải là quản trị viên hệ thống (idempotent)', + requiredRole: 'Vai trò yêu cầu: {role}', + valueNull: '(chưa đặt)' + }, + expanded: { + actorId: 'ID người thực hiện', + targetUserId: 'ID người dùng mục tiêu', + targetType: 'Loại đối tượng', + targetId: 'ID đối tượng', + details: 'Chi tiết thô' + }, + drawer: { + sectionSummary: 'Tóm tắt sự kiện', + sectionIdentifiers: 'Mã định danh liên quan', + sectionRequest: 'Yêu cầu', + targetChange: 'Thay đổi', + requestMethod: 'Phương thức' + }, + tabLabel: 'Audit Log', + description: 'Sự kiện cấp nền tảng: thay đổi cài đặt hệ thống, cấp/thu hồi quyền quản trị viên hệ thống, đồng bộ hạn mức hàng loạt. Mới nhất xếp trước.', + refresh: 'Làm mới', + retry: 'Thử lại', + loading: 'Đang tải…', + end: 'Đã hiển thị toàn bộ.', + empty: 'Chưa có sự kiện nhật ký cấp nền tảng nào.', + forbidden: 'Không có quyền xem Audit Log của nền tảng.', + systemActor: 'Hệ thống', + errors: { + generic: 'Không thể tải Audit Log' + }, + actorRole: { + system_admin: 'Quản trị viên hệ thống' + }, + columns: { + time: 'Thời gian', + actor: 'Tác nhân', + action: 'Sự kiện', + target: 'Đối tượng', + path: 'Yêu cầu', + outcome: 'Kết quả' + } + }, + listConfirm: { + ssrf: { + whitelist: { + add: { + confirmBtn: 'Thêm', + header: 'Thêm mục vào danh sách cho phép SSRF', + body: 'Thêm {entry} vào danh sách cho phép SSRF? Các host / IP / CIDR khớp với mục này sẽ bỏ qua lớp bảo vệ SSRF và có thể cho phép agent truy cập các dịch vụ nội bộ. Chỉ thêm các mục mà bạn hoàn toàn tin cậy.' + }, + remove: { + header: 'Xóa mục danh sách cho phép SSRF', + body: 'Xóa {entry} khỏi danh sách cho phép SSRF? Sau khi xóa, mục này sẽ tiếp tục bị cơ chế bảo vệ SSRF chặn.', + confirmBtn: 'Xóa' + } + } + } + }, + messages: { + loadFailed: 'Không thể tải cài đặt hệ thống', + saveSuccess: 'Đã lưu', + saveFailed: 'Lưu thất bại' + }, + reset: { + label: 'Đặt lại', + tooltip: 'Xóa giá trị ghi đè trên giao diện và quay về biến môi trường hoặc mặc định', + confirmBtn: 'Xác nhận đặt lại', + confirmBody: 'Đặt lại "{label}"? Thao tác này sẽ xóa giá trị ghi đè trong cơ sở dữ liệu và quay về biến môi trường hoặc mặc định.', + success: 'Đã đặt lại về mặc định', + failed: 'Đặt lại thất bại' + }, + admins: { + label: 'Quản trị viên hệ thống', + description: 'Người dùng có quyền cấp nền tảng. Nhập email và nhấn Enter để cấp quyền; nhấp × để thu hồi. Tài khoản của bạn là quản trị viên và không hiển thị trong danh sách — bạn không thể tự thu hồi quyền của mình.', + placeholder: 'Nhập email người dùng và nhấn Enter', + loadFailed: 'Không thể tải danh sách quản trị viên hệ thống', + saveSuccess: 'Đã cập nhật quản trị viên hệ thống', + saveFailed: 'Cập nhật quản trị viên hệ thống thất bại', + confirm: { + promote: { + header: 'Chỉ định quản trị viên hệ thống', + body: 'Chỉ định {email} làm quản trị viên hệ thống? Người dùng này sẽ nhận các đặc quyền cấp nền tảng: truy cập mọi không gian làm việc, cài đặt hệ thống và danh sách quản trị viên.', + confirmBtn: 'Chỉ định' + }, + revoke: { + header: 'Thu hồi quyền quản trị viên hệ thống', + body: 'Thu hồi quyền quản trị viên hệ thống của {email}? Họ sẽ mất quyền truy cập vào tất cả tính năng cấp hệ thống.', + confirmBtn: 'Thu hồi' + } + } + }, + passwordReset: { + label: 'Đặt lại mật khẩu người dùng', + description: 'Đặt mật khẩu mới cho người dùng không thể đăng nhập. Thao tác này sẽ hủy tất cả phiên hoạt động hiện tại, yêu cầu họ đăng nhập lại bằng mật khẩu mới.', + action: 'Đặt lại mật khẩu', + dialogTitle: 'Đặt lại mật khẩu người dùng khác', + warning: 'Đây là thao tác có độ rủi ro cao. Vui lòng kiểm tra kỹ email. Bạn không thể đặt lại mật khẩu của chính mình tại đây.', + emailLabel: 'Email người dùng', + emailPlaceholder: 'Nhập email của người dùng cần đặt lại', + newPasswordLabel: 'Mật khẩu mới', + newPasswordPlaceholder: 'Nhập mật khẩu mới', + confirmPasswordLabel: 'Xác nhận mật khẩu mới', + confirmPasswordPlaceholder: 'Nhập lại mật khẩu mới', + confirmBtn: 'Xác nhận đặt lại', + success: 'Đã đặt lại mật khẩu; các phiên đăng nhập cũ đã bị hủy', + failed: 'Đặt lại mật khẩu thất bại' + }, + createUser: { + label: 'Tạo người dùng', + description: 'Khởi tạo tài khoản người dùng cục bộ mới. Nếu chế độ không gian làm việc mặc định được đặt là "tạo cá nhân", người dùng sẽ nhận được một không gian làm việc cá nhân tương tự như khi tự đăng ký.', + action: 'Tạo người dùng', + dialogTitle: 'Tạo người dùng mới', + warning: 'Đây là thao tác có độ rủi ro cao. Vui lòng kiểm tra kỹ tên người dùng và email — đây là thông tin dùng để đăng nhập.', + usernameLabel: 'Tên người dùng', + usernamePlaceholder: '2-50 ký tự', + emailLabel: 'Email', + emailPlaceholder: 'Nhập địa chỉ email hợp lệ', + autoGenerateLabel: 'Tự động tạo mật khẩu ngẫu nhiên', + newPasswordLabel: 'Mật khẩu mới', + newPasswordPlaceholder: '8-32 ký tự, bao gồm chữ cái và chữ số', + confirmPasswordLabel: 'Xác nhận mật khẩu mới', + confirmPasswordPlaceholder: 'Nhập lại mật khẩu mới', + confirmBtn: 'Tạo người dùng', + success: 'Đã tạo người dùng', + successIdempotent: 'Người dùng đã tồn tại; không có thay đổi nào', + missingPassword: 'Đã tạo người dùng nhưng không nhận được mật khẩu đã tạo. Hãy đặt lại mật khẩu để khôi phục quyền truy cập.', + failed: 'Tạo người dùng thất bại', + validation: { + usernameRequired: 'Vui lòng nhập tên người dùng', + usernameLength: 'Tên người dùng phải từ 2-50 ký tự', + emailRequired: 'Vui lòng nhập email', + emailInvalid: 'Địa chỉ email không hợp lệ', + passwordRequired: 'Vui lòng nhập mật khẩu mới', + passwordLength: 'Mật khẩu phải từ 8-32 ký tự', + passwordLetter: 'Mật khẩu phải chứa ít nhất một chữ cái', + passwordNumber: 'Mật khẩu phải chứa ít nhất một chữ số', + confirmRequired: 'Vui lòng nhập lại mật khẩu mới', + passwordMismatch: 'Mật khẩu không khớp' + }, + generated: { + successTitle: 'Đã tạo người dùng', + successBody: 'Mật khẩu ngẫu nhiên đã được tạo cho người dùng này. Mật khẩu chỉ hiển thị một lần duy nhất.', + usernameLabel: 'Tên người dùng', + emailLabel: 'Email', + passwordLabel: 'Mật khẩu đã tạo', + copyBtn: 'Sao chép thông tin tài khoản', + copySuccess: 'Đã sao chép thông tin tài khoản vào khay nhớ tạm', + acknowledgeBtn: 'Tôi đã lưu mật khẩu' + } + }, + bulkApply: { + label: 'Áp dụng cho mọi không gian làm việc hiện có', + tooltip: 'Mặc định việc lưu giá trị chỉ áp dụng cho không gian làm việc mới; nhấp vào đây để ghi đè cho toàn bộ không gian làm việc hiện có.', + confirmBtn: 'Xác nhận áp dụng', + confirmBody: 'Ghi đè hạn mức lưu trữ của mọi không gian làm việc hiện có thành {value} GB. Các không gian làm việc đã được điều chỉnh thủ công trước đó cũng sẽ bị ghi đè. Tiếp tục?', + success: 'Đã cập nhật hạn mức lưu trữ cho {count} không gian làm việc thành {gb} GB', + failed: 'Áp dụng cho toàn bộ không gian làm việc thất bại' + }, + keyLabels: { + auth: { + registration_mode: 'Chế độ đăng ký', + default_tenant_mode: 'Khởi tạo không gian làm việc mặc định', + complex_password_enabled: 'Yêu cầu mật khẩu phức tạp' + }, + ssrf: { + whitelist: 'Danh sách cho phép bảo vệ SSRF' + }, + sandbox: { + docker_enabled: 'Bật Sandbox Docker' + }, + tenant: { + max_owned_per_user: 'Số không gian làm việc tối đa mỗi người dùng', + self_service_creation_enabled: 'Cho phép tự tạo không gian làm việc', + default_storage_quota_gb: 'Dung lượng lưu trữ mặc định cho không gian làm việc mới (GB)', + auto_create_api_key: 'Tự động tạo khóa API cho không gian làm việc mới', + auto_accept_invitation: 'Tự động chấp nhận lời mời cho người dùng đã đăng ký' + }, + asynq: { + core_concurrency: 'Mức đồng thời phân tích cốt lõi đảm bảo', + postprocess_concurrency: 'Mức đồng thời hậu xử lý', + enrichment_concurrency: 'Mức đồng thời làm giàu dữ liệu đảm bảo', + maintenance_concurrency: 'Mức đồng thời bảo trì', + shared_concurrency: 'Mức đồng thời dùng chung linh hoạt', + wiki_concurrency: 'Mức đồng thời luồng xử lý Wiki' + }, + model: { + max_concurrency: 'Giới hạn đồng thời mặc định trên mỗi mô hình' + } + }, + keyDescriptions: { + auth: { + registration_mode: 'Chế độ đăng ký. Đăng ký mở cho phép bất kỳ ai tạo tài khoản; đăng ký theo lời mời yêu cầu liên kết lời mời hợp lệ; vô hiệu hóa đăng ký sẽ ngăn tạo tài khoản mới nhưng tài khoản hiện có vẫn có thể chấp nhận lời mời. Thay đổi có hiệu lực ngay lập tức.', + default_tenant_mode: 'Khởi tạo không gian làm việc sau khi đăng ký công khai. create_personal sẽ tạo một không gian làm việc do người dùng làm Chủ sở hữu; tenantless chỉ tạo tài khoản cho đến khi người dùng chấp nhận lời mời hoặc tự tạo không gian làm việc. Chỉ áp dụng cho người dùng mới.', + complex_password_enabled: 'Yêu cầu mật khẩu phức tạp hay không. Khi bật, mật khẩu phải chứa chữ hoa, chữ thường, số và ký tự đặc biệt. Thay đổi có hiệu lực ngay và chỉ áp dụng cho người dùng mới đăng ký hoặc khi đổi/đặt lại mật khẩu. Ký tự đặc biệt bao gồm {specialChars}' + }, + ssrf: { + whitelist: 'Danh sách cho phép bảo vệ SSRF. Chấp nhận các mục như example.com / *.foo.com / 10.0.0.0/8 / 2001:db8::1. Có hiệu lực ngay sau khi lưu. Biến môi trường SSRF_WHITELIST_EXTRA do người triển khai quản lý và không bị ghi đè tại đây.' + }, + sandbox: { + docker_enabled: 'Cho phép backend Sandbox Docker. docker.sock cục bộ tương đương với quyền root trên máy chủ lưu trữ, do đó cài đặt này mặc định tắt. Chỉ quản trị viên hệ thống mới có thể bật; thay đổi có hiệu lực ngay lập tức. Chỉ bật trên cài đặt đơn nút riêng tư có mount socket daemon hoặc sử dụng điểm cuối từ xa tcp:// được bảo vệ bằng TLS.' + }, + tenant: { + max_owned_per_user: 'Số lượng không gian làm việc tối đa mà người dùng không phải superuser có thể sở hữu thông qua tự tạo. Được kiểm tra mỗi khi tạo không gian làm việc và có hiệu lực ngay sau khi lưu. Đặt 0 sẽ dùng mặc định hệ thống là 10; giá trị âm sẽ bỏ giới hạn hoàn toàn (không khuyến nghị cho môi trường công khai).', + self_service_creation_enabled: 'Cho phép người dùng không phải superuser tự tạo không gian làm việc hay không. Khi tắt, người dùng thông thường chỉ có thể tham gia không gian làm việc có sẵn qua lời mời; superuser liên không gian làm việc không bị ảnh hưởng. Có hiệu lực ngay lập tức.', + default_storage_quota_gb: 'Dung lượng lưu trữ mặc định (GB) được chỉ định khi tạo không gian làm việc mới, bao gồm vector, tệp gốc, văn bản, chỉ mục và dữ liệu liên quan. Chỉ đọc tại thời điểm tạo — thay đổi chỉ áp dụng cho các không gian làm việc mới tạo và không hồi tố cho các không gian làm việc hiện có. Đặt 0 hoặc giá trị âm sẽ dùng mặc định là 10 GB.', + auto_create_api_key: 'Tự động tạo khóa API full_access cho không gian làm việc mới và trả về token dạng văn bản thuần trong phản hồi tạo. Chỉ dùng cho các tích hợp phụ thuộc vào cơ chế cũ; mặc định tắt và khuyến nghị nên tạo khóa API thủ công rõ ràng.', + auto_accept_invitation: 'Khi bật, việc mời một người dùng đã đăng ký qua email sẽ thêm họ làm thành viên ngay lập tức thay vì chờ xác nhận qua hộp thư. Khi tắt, người được mời phải chấp nhận từ hộp thư đến. Có hiệu lực ngay lập tức.' + }, + asynq: { + core_concurrency: 'Mức đồng thời đảm bảo trên mỗi tiến trình cho việc phân tích tài liệu và thủ công. Tiến trình cốt lõi cũng có thể mượn từ hồ linh hoạt dùng chung. Tối thiểu là 1; yêu cầu khởi động lại dịch vụ.', + postprocess_concurrency: 'Mức đồng thời chuyên dụng trên mỗi tiến trình để hoàn tất phân tích nhẹ và phân nhánh làm giàu dữ liệu. Tối thiểu là 1; yêu cầu khởi động lại dịch vụ.', + enrichment_concurrency: 'Mức đồng thời đảm bảo trên mỗi tiến trình để tạo tóm tắt, hình ảnh, đồ thị và câu hỏi. Làm giàu dữ liệu cũng có thể mượn từ hồ linh hoạt dùng chung. Tối thiểu là 1; yêu cầu khởi động lại dịch vụ.', + maintenance_concurrency: 'Mức đồng thời trên mỗi tiến trình cho việc đồng bộ nguồn, tác vụ hàng loạt và dọn dẹp, được cô lập hoàn toàn khỏi luồng tương tác của người dùng. Tối thiểu là 1; yêu cầu khởi động lại dịch vụ.', + shared_concurrency: 'Mức đồng thời linh hoạt trên mỗi tiến trình được chia sẻ giữa phân tích cốt lõi và làm giàu dữ liệu; bên nào có tác vụ tồn đọng sẽ tự động mượn. Tối thiểu là 1; yêu cầu khởi động lại dịch vụ.', + wiki_concurrency: 'Mức đồng thời trên mỗi tiến trình cho nhóm worker Wiki chuyên dụng, tách biệt khỏi các tác vụ thượng nguồn. Tối thiểu là 1; yêu cầu khởi động lại dịch vụ.' + }, + model: { + max_concurrency: 'Giới hạn mặc định cho các lệnh gọi chạy nền đồng thời (nạp/làm giàu) đến một mô hình duy nhất, theo ID mô hình và được chia sẻ trên các bản sao (replica). Được kiểm tra ở mỗi lượt gọi và áp dụng ngay mà không cần khởi động lại. Đặt 0 hoặc giá trị âm sẽ tắt giới hạn mặc định (mỗi mô hình vẫn tuân theo giới hạn riêng được cấu hình trong quản lý mô hình). Chỉ ảnh hưởng đến tác vụ nền, không ảnh hưởng đến trò chuyện trực tiếp.' + } + }, + enumLabels: { + auth: { + registration_mode: { + self_serve: 'Tự đăng ký (bất kỳ ai cũng có thể đăng ký)', + invite_only: 'Đã vô hiệu hóa đăng ký (tài khoản hiện có có thể chấp nhận lời mời)', + invite_register: 'Đăng ký theo lời mời (yêu cầu liên kết hợp lệ)' + }, + default_tenant_mode: { + create_personal: 'Tạo không gian làm việc cá nhân', + tenantless: 'Không tạo không gian làm việc' + } + } + }, + confirm: { + confirmBtn: 'Xác nhận lưu', + cancelBtn: 'Hủy', + emptyValue: '(trống)', + bodyAuthRegistrationMode: 'Sắp thay đổi "{label}" thành: {value}\n\nNếu chuyển sang self_serve, bất kỳ ai trên internet đều có thể đăng ký tài khoản — vui lòng xác nhận đây là hành động có chủ đích.', + bodySandboxDockerEnabled: 'Khi bật, quản trị viên không gian làm việc có thể trỏ Sandbox tới Docker daemon cục bộ. File docker.sock cục bộ tương đương quyền root trên máy chủ lưu trữ. Chỉ sử dụng cài đặt này trên cấu hình đơn nút riêng tư có gắn daemon hoặc sử dụng điểm cuối từ xa tcp:// được bảo vệ bằng TLS.' + } + } + }, + model: { + editor: { + maxOutputTokensDesc: 'Giới hạn output mỗi phản hồi. Để trống để dùng mặc định từ danh mục.', + catalog: { + reasoning: 'Suy luận', + vision: 'Thị giác (Vision)', + hint: 'Chọn mô hình từ danh mục nhà cung cấp hoặc nhập tên tuỳ chỉnh.' + }, + resolved: { + title: 'Cách gọi mô hình này', + empty: 'Nhập nhà cung cấp và tên mô hình để xem phương thức gọi', + failed: 'Phân giải thất bại', + protocol: 'Giao thức yêu cầu', + catalog: 'Khả năng lấy từ', + catalogedYes: 'Hồ sơ mô hình tích hợp sẵn', + catalogedNo: 'Mặc định từ nhà cung cấp (mô hình không có trong danh mục)', + endpoint: 'Endpoint yêu cầu', + thinkingFormat: 'Cờ bật/tắt suy luận gửi dưới dạng', + thinkingLevels: 'Mức độ suy luận hỗ trợ', + noThinking: 'Mô hình không hỗ trợ suy luận' + }, + advanced: { + toggle: 'Nâng cao', + api: { + label: 'Ghi đè giao thức', + auto: 'Tự động (từ nhà cung cấp / URL)', + desc: 'Bắt buộc dùng một giao thức; thông thường không cần thiết.' + }, + remoteModelName: { + label: 'Tên mô hình từ xa', + placeholder: 'Để trống để dùng tên mô hình', + desc: 'ID mô hình thực tế gửi đến nhà cung cấp khi khác với tên ở trên.' + }, + legacyThinking: { + label: 'Định dạng tham số suy luận (cũ)', + catalog: 'Theo mặc định danh mục (khuyên dùng)', + none: 'Không gửi trường suy luận', + desc: 'Mô hình này vẫn dùng cài đặt thinking_control cũ. Chọn "Theo mặc định danh mục" để hệ thống tự quyết định.' + }, + compat: { + label: 'Ghi đè tương thích giao thức (JSON)', + placeholder: '{\'{\'} "max_tokens_field": "max_tokens" {\'}\'}', + desc: 'Chỉ dùng khi endpoint khác với mặc định danh mục; chỉ điền các trường cần đổi. Để trống nếu không ghi đè.', + docLink: 'Tài liệu tham chiếu trường', + invalid: 'JSON không hợp lệ', + mustBeObject: 'Phải là một đối tượng JSON' + } + }, + addTitle: 'Thêm mô hình', + editTitle: 'Chỉnh sửa mô hình', + sectionType: 'Loại mô hình', + typeLabel: 'Loại mô hình', + sectionSource: 'Nguồn', + sectionProvider: 'Cài đặt nhà cung cấp', + sectionAdvanced: 'Tuỳ chọn nâng cao', + sourceLabel: 'Nguồn mô hình', + sourceLocal: 'Ollama', + sourceRemote: 'API', + description: { + chat: 'Cấu hình mô hình ngôn ngữ lớn cho hội thoại', + embedding: 'Cấu hình mô hình embedding để Embedding văn bản', + rerank: 'Cấu hình mô hình Rerank kết quả', + vllm: 'Cấu hình mô hình ngôn ngữ - thị giác cho xử lý đa phương thức', + asr: 'Cấu hình mô hình chuyển giọng nói thành văn bản', + default: 'Cấu hình thông tin mô hình' + }, + modelNamePlaceholder: { + local: 'VD: llama2:latest', + remote: 'VD: gpt-4, claude-3-opus', + localVllm: 'VD: llava:latest', + remoteVllm: 'VD: gpt-4-vision-preview', + remoteAsr: 'VD: whisper-1' + }, + baseUrlLabel: 'Base URL', + displayNameLabel: 'Tên hiển thị (tuỳ chọn)', + displayNamePlaceholder: 'VD: Mô hình Hỏi đáp Hỗ trợ', + displayNameDesc: 'Chỉ dùng trên giao diện. Các lệnh gọi runtime vẫn dùng tên mô hình phía trên.', + baseUrlPlaceholder: 'VD: https://api.openai.com/v1', + baseUrlPlaceholderVllm: 'VD: http://localhost:11434/v1', + baseUrlPlaceholderAsr: 'VD: https://api.openai.com/v1', + apiKeyOptional: 'API Key (tuỳ chọn)', + apiKeyPlaceholder: 'Nhập API Key', + customHeadersLabel: 'Request Header tuỳ chỉnh (tuỳ chọn)', + customHeadersDesc: 'Các HTTP header gửi kèm trong request API (VD: xác thực qua gateway doanh nghiệp hoặc tracing). Bỏ qua các header mặc định như Authorization / Content-Type.', + customHeadersAdd: 'Thêm Header', + customHeadersKeyPlaceholder: 'Tên header', + customHeadersValuePlaceholder: 'Giá trị header', + testing: 'Đang kiểm tra...', + testConnection: 'Kiểm tra kết nối', + downloadLabel: 'Tải xuống: {keyword}', + refreshList: 'Làm mới danh sách', + dimensionLabel: 'Số chiều vector', + dimensionPlaceholder: 'VD: 1536', + checkDimension: 'Nhận diện số chiều', + dimensionDetected: 'Nhận diện thành công. Số chiều vector: {value}', + dimensionFailed: 'Nhận diện thất bại, vui lòng nhập số chiều thủ công', + remoteDimensionDetected: 'Số chiều vector đã nhận diện: {value}', + dimensionOverrideLabel: 'Tuỳ chỉnh số chiều output', + dimensionOverrideDesc: 'Chỉ bật nếu tài liệu nhà cung cấp xác nhận mô hình hỗ trợ tham số dimensions.', + supportsVisionLabel: 'Hỗ trợ Thị giác / Đa phương thức', + supportsVisionDesc: 'Mô hình có chấp nhận đầu vào hình ảnh và đa phương thức hay không', + contextWindowLabel: 'Context Window', + contextWindowPlaceholder: 'Mặc định {value}', + contextWindowDesc: 'Số token tối đa cho mỗi request. Dùng để nén lịch sử Agent. Để trống để nhận mặc định 200.000 (200K). Hãy nhập đúng theo nhà cung cấp — ước tính quá lớn sẽ khiến hệ thống không thể tự nén và bị từ chối request.', + contextWindowDefaultHint: 'Chưa đặt, dùng mặc định {value}', + contextWindowTokens: '{count} token', + maxConcurrencyLabel: 'Giới hạn tác vụ nền đồng thời', + maxConcurrencyPlaceholder: '0 = dùng mặc định hệ thống', + maxConcurrencyDesc: 'Giới hạn số lệnh gọi nền (nạp/làm giàu dữ liệu) đồng thời tới mô hình này, chia sẻ trên mọi bản sao. Nhập 0 hoặc để trống để theo mặc định; không ảnh hưởng tới hội thoại trực tiếp.', + dimensionHint: 'Đã chọn mô hình. Bấm "Nhận diện số chiều" để tự động lấy số chiều vector.', + loadModelListFailed: 'Không thể tải danh sách mô hình', + listRefreshed: 'Đã làm mới danh sách', + fillModelAndUrl: 'Vui lòng nhập định danh mô hình và Base URL trước', + remoteBaseUrlRequired: 'Mô hình API yêu cầu phải có Base URL', + unsupportedModelType: 'Loại mô hình không được hỗ trợ', + saveAndClose: 'Lưu và đóng', + testDraftHint: 'Kiểm tra cài đặt kết nối hiện tại mà không cần lưu.', + testDraftEditHint: 'Kiểm tra cài đặt kết nối bằng API key đã lưu riêng.', + testStale: 'Cài đặt đã thay đổi. Vui lòng kiểm tra lại.', + connectionSuccess: 'Kết nối thành công', + maxOutputTokensLabel: 'Số token đầu ra tối đa', + maxOutputTokensPlaceholder: 'Để trống để dùng mặc định theo danh mục', + connectionFailed: 'Kết nối thất bại', + connectionConfigError: 'Kết nối thất bại, vui lòng kiểm tra lại cấu hình', + downloadStarted: 'Bắt đầu tải {name}', + downloadCompleted: 'Tải thành công {name}', + downloadFailed: 'Tải thất bại {name}', + downloadStartFailed: 'Không thể bắt đầu tải xuống', + ollamaUnavailable: 'Dịch vụ Ollama không khả dụng, không thể chọn mô hình cục bộ', + ollamaNotSupportRerank: 'Ollama không hỗ trợ mô hình Rerank, vui lòng dùng API từ xa', + goToOllamaSettings: 'Mở Cài đặt', + validation: { + extraFieldRequired: 'Vui lòng điền {name}', + modelNameRequired: 'Vui lòng nhập tên mô hình', + modelNameEmpty: 'Tên mô hình không được để trống', + modelNameMax: 'Tên mô hình không được vượt quá 100 ký tự', + baseUrlRequired: 'Vui lòng nhập Base URL', + baseUrlEmpty: 'Base URL không được để trống', + baseUrlInvalid: 'Base URL không hợp lệ, vui lòng nhập URL chính xác' + }, + providerLabel: 'Nhà cung cấp', + providerPlaceholder: 'Chọn nhà cung cấp mô hình', + providerDocs: 'Xem tài liệu mô hình {provider}' + }, + reasoning: { + levels: { + off: 'Tắt', + auto: 'Tự động', + minimal: 'Tối thiểu', + low: 'Thấp', + medium: 'Vừa', + high: 'Cao', + xhigh: 'Rất cao', + max: 'Tối đa' + }, + levelDescriptions: { + off: 'Tắt suy luận; không gửi tham số suy luận', + auto: 'Độ sâu mặc định của nhà cung cấp; mô hình tự quyết định mức độ suy luận', + minimal: 'Suy luận ít nhất, phản hồi nhanh nhất', + low: 'Suy luận nhẹ', + medium: 'Suy luận vừa phải', + high: 'Suy luận sâu, phản hồi chậm hơn', + xhigh: 'Ngân sách suy luận rất cao (chỉ hỗ trợ một số mô hình)', + max: 'Ngân sách suy luận tối đa (chỉ hỗ trợ một số mô hình)' + } + }, + modelName: 'Tên mô hình', + defaultTag: 'Mặc định', + addModelInSettings: 'Đi tới Cài đặt chung để thêm mô hình', + loadFailed: 'Không thể tải danh sách mô hình', + selectModelPlaceholder: 'Chọn một mô hình', + searchPlaceholder: 'Tìm kiếm mô hình...', + builtinTag: 'Tích hợp sẵn' + }, + mcp: { + testResult: { + title: 'Kết quả kiểm tra: {name}', + connectionSuccess: 'Kết nối thành công', + connectionFailed: 'Kết nối thất bại', + toolsTitle: 'Công cụ khả dụng', + resourcesTitle: 'Tài nguyên khả dụng', + descriptionLabel: 'Mô tả', + schemaLabel: 'Schema tham số', + emptyDescription: 'Dịch vụ này không cung cấp công cụ hay tài nguyên nào', + requireApproval: 'Yêu cầu phê duyệt thủ công', + requireApprovalTip: 'Khi bật, agent sẽ tạm dừng trước khi gọi công cụ này cho đến khi bạn phê duyệt — dùng cho thao tác ghi, xóa dữ liệu, v.v.', + approvalSaveFailed: 'Lưu cài đặt phê duyệt thất bại', + toolEnabled: 'Bật công cụ', + toolEnabledTip: 'Khi tắt, agent sẽ không nhìn thấy hoặc gọi công cụ này', + toolEnabledSaveFailed: 'Lưu cài đặt công cụ thất bại' + } + }, + error: { + networkError: 'Lỗi mạng, vui lòng kiểm tra kết nối', + requestTimeout: 'Yêu cầu quá thời gian chờ. Tệp lớn hoặc kết nối chậm có thể cần thử lại.', + invalidCredentials: 'Tên đăng nhập hoặc mật khẩu không đúng', + tokenRefreshFailed: 'Làm mới phiên thất bại', + pleaseRelogin: 'Vui lòng đăng nhập lại', + fileSizeExceeded: 'Kích thước tệp không được vượt quá {size}MB!', + unsupportedFileType: 'Định dạng tệp không được hỗ trợ!', + invalidFileType: 'Loại tệp không hợp lệ!', + invalidImageLink: 'Liên kết hình ảnh không hợp lệ', + missingKbId: 'Thiếu ID kho tri thức', + tokenNotFound: 'Không tìm thấy phiên đăng nhập, vui lòng đăng nhập lại', + streamFailed: 'Kết nối luồng thất bại', + auth: { + loginFailed: 'Đăng nhập thất bại', + registerFailed: 'Đăng ký thất bại', + getUserFailed: 'Không thể lấy thông tin người dùng', + getTenantFailed: 'Không thể lấy thông tin không gian làm việc', + updatePreferencesFailed: 'Cập nhật tùy chọn thất bại', + refreshTokenFailed: 'Làm mới mã phiên thất bại', + logoutFailed: 'Đăng xuất thất bại', + validateTokenFailed: 'Xác thực phiên thất bại' + }, + model: { + createFailed: 'Tạo mô hình thất bại', + getFailed: 'Không thể lấy thông tin mô hình', + updateFailed: 'Cập nhật mô hình thất bại', + deleteFailed: 'Xóa mô hình thất bại' + }, + tenant: { + listFailed: 'Không thể lấy danh sách không gian làm việc', + searchFailed: 'Tìm kiếm không gian làm việc thất bại', + getApiPrincipalConfigFailed: 'Không thể lấy cấu hình API principal', + updateApiPrincipalConfigFailed: 'Cập nhật cấu hình API principal thất bại', + createApiPrincipalTestTokenFailed: 'Tạo token kiểm tra API thất bại', + updateFailed: 'Cập nhật thông tin không gian làm việc thất bại', + deleteFailed: 'Xóa không gian làm việc thất bại' + }, + initialization: { + checkFailed: 'Kiểm tra thất bại', + testFailed: 'Kiểm thử thất bại' + } + }, + language: { + zhCN: '简体中文', + enUS: 'English', + ruRU: 'Русский', + koKR: '한국어', + jaJP: '日本語', + selectLanguage: 'Chọn ngôn ngữ', + language: 'Ngôn ngữ', + languageDescription: 'Chọn ngôn ngữ hiển thị giao diện', + languageSaved: 'Đã lưu cài đặt ngôn ngữ', + viVN: 'Tiếng Việt' + }, + general: { + title: 'Cài đặt chung', + allSettings: 'Tất cả cài đặt', + personalSettings: 'Cài đặt cá nhân', + helpAndDocs: 'Trợ giúp & Tài liệu', + description: 'Cấu hình ngôn ngữ, giao diện và các tùy chọn cơ bản', + settings: 'Cài đặt', + close: 'Đóng cài đặt' + }, + theme: { + theme: 'Giao diện', + themeDescription: 'Chọn giao diện hiển thị, hỗ trợ tự động đồng bộ theo hệ thống', + light: 'Sáng', + dark: 'Tối', + system: 'Theo hệ thống', + selectTheme: 'Chọn giao diện' + }, + font: { + uiFont: 'Phông chữ giao diện', + uiFontDescription: 'Phông chữ dùng cho menu, văn bản, nút bấm và hầu hết giao diện', + monoFont: 'Phông chữ mã nguồn', + monoFontDescription: 'Dùng cho khối mã, lệnh terminal, API key, đường dẫn tệp và văn bản kỹ thuật. Ký tự có cùng độ rộng giúp phân biệt rõ 0 với O và 1 với l.', + selectFont: 'Chọn phông chữ', + sansPreview: 'The quick brown fox jumps — Aa Gg Oo 0123', + monoPreview: 'const msg = \'Hello\'; // 0O1l', + sans: { + system: 'Mặc định hệ thống', + pingfang: 'PingFang SC', + georgia: 'Georgia (Serif)', + yahei: 'Microsoft YaHei', + times: 'Times New Roman (Serif)', + 'noto-cjk': 'Noto Sans CJK', + 'dejavu-serif': 'DejaVu Serif (Serif)', + 'sans-serif': 'Sans-Serif phổ thông' + }, + mono: { + system: 'Mặc định hệ thống', + menlo: 'Menlo', + monaco: 'Monaco', + consolas: 'Consolas', + cascadia: 'Cascadia Code', + 'dejavu-mono': 'DejaVu Sans Mono', + 'liberation-mono': 'Liberation Mono', + monospace: 'Monospace phổ thông' + }, + fontSize: 'Cỡ chữ', + fontSizeDescription: 'Thu phóng toàn bộ giao diện (văn bản, biểu tượng, khoảng cách) và áp dụng ngay', + size: { + small: 'Nhỏ', + normal: 'Tiêu chuẩn', + large: 'Lớn' + } + }, + platform: { + subtitle: 'Nền tảng tri thức doanh nghiệp vận hành bởi LLM', + description: 'Truy xuất RAG, suy luận agent và kho tri thức Wiki — giúp thấu hiểu tài liệu và đưa vào vận hành thực tế', + rag: 'Tạo sinh tăng cường truy xuất (RAG)', + agent: 'ReAct Agent', + wiki: 'Kho tri thức Wiki', + hybridSearch: 'Tìm kiếm kết hợp', + multimodalParsing: 'Phân tích tài liệu đa phương thức', + hybridSearchEngine: 'Tìm kiếm kết hợp + Đồ thị tri thức', + ragQandA: 'Hỏi đáp với ReAct Agent', + independentTenant: 'Không gian làm việc độc lập', + fullApiAccess: 'Truy cập toàn bộ API', + knowledgeBaseManagement: 'Quản lý kho tri thức', + carousel: { + agenticRagTitle: 'Agentic RAG', + agenticRagDesc: 'Suy luận ReAct + gọi công cụ + tư duy đa bước', + hybridSearchTitle: 'Chiến lược tìm kiếm kết hợp', + hybridSearchDesc: 'BM25 + Vector + Đồ thị tri thức', + wikiTitle: 'Kho tri thức Wiki', + wikiDesc: 'Chắt lọc tài liệu thành hệ thống tri thức liên kết chặt chẽ', + smartDocRetrievalTitle: 'Truy xuất tài liệu thông minh', + smartDocRetrievalDesc: 'Phân tích đa định dạng PDF/Word/Hình ảnh' + } + }, + time: { + today: 'Hôm nay', + yesterday: 'Hôm qua', + last7Days: '7 ngày qua', + last30Days: '30 ngày qua', + lastYear: 'Năm qua', + earlier: 'Trước đó', + pinned: 'Đã ghim' + }, + upload: { + uploadDocument: 'Tải tài liệu lên', + uploadFolder: 'Tải thư mục lên', + onlineEdit: 'Chỉnh sửa trực tuyến', + deleteRecord: 'Xóa bản ghi' + }, + uploadTasks: { + panelLabel: 'Tệp tải lên', + titleUploading: 'Đang tải lên {done}/{total}', + titleParsing: 'Đang phân tích {done}/{total}', + titleDone: 'Hoàn tất', + titleDoneWithIssues: '{ok} hoàn tất, {bad} chưa xong', + titleCancelled: 'Đã hủy tải lên', + destination: 'Đích đến: {name}', + destinationMany: 'Đích đến: {count} kho tri thức', + remaining: 'còn khoảng {time}', + eta: { + seconds: '{n} giây', + minutes: '{n} phút', + hours: '{n} giờ' + }, + hintUploading: 'Vui lòng giữ nguyên trang này cho đến khi tải lên hoàn tất', + hintParsing: 'Đã tải lên tất cả tệp. Quá trình phân tích tiếp tục chạy ngầm, bạn có thể rời khỏi trang', + legend: { + ready: 'Có thể tìm kiếm', + active: 'Đang xử lý', + waiting: 'Chờ xử lý', + failed: 'Thất bại', + duplicate: 'Đã tồn tại' + }, + filterAll: 'Tất cả', + filterIssues: 'Chưa hoàn tất', + phaseWaiting: 'Chờ xử lý', + phaseSaving: 'Đang lưu…', + phasePending: 'Chờ phân tích', + phaseParsing: 'Đang phân tích', + phaseFinalizing: 'Có thể tìm kiếm, đang tối ưu', + phaseReady: 'Hoàn tất', + phaseUploadFailed: 'Tải lên thất bại', + phaseParseFailed: 'Phân tích thất bại', + phaseDuplicate: 'Tệp đã tồn tại trong kho tri thức này', + phaseCancelled: 'Đã hủy', + phaseDeleted: 'Đã xóa', + cancel: 'Hủy', + cancelAll: 'Hủy tất cả', + retry: 'Thử lại', + retryFailed: 'Thử lại ({count})', + open: 'Mở', + collapse: 'Thu gọn', + expand: 'Mở rộng', + close: 'Đóng', + closeConfirm: 'Đóng sẽ dừng các tệp chưa tải lên xong ({count})', + closeConfirmOk: 'Hủy tải lên', + closeConfirmKeep: 'Tiếp tục tải lên' + }, + agentSettings: { + modelRecommendation: { + title: 'Gợi ý mô hình' + }, + maxIterations: { + desc: 'Giới hạn số bước suy luận cho mỗi tác vụ. Không giới hạn sẽ tiếp tục cho đến khi mô hình tự dừng hoặc bạn dừng lại.' + }, + thinkingModel: { + desc: 'LLM dùng cho Agent suy luận và lập kế hoạch' + }, + rerankModel: { + desc: 'Rerank kết quả tìm kiếm và chuẩn hóa điểm liên quan' + }, + temperature: { + desc: 'Kiểm soát tính ngẫu nhiên của kết quả. 0 là xác định nhất; 1 là ngẫu nhiên nhất' + }, + allowedTools: { + desc: 'Các công cụ hiện được bật cho Agent' + }, + systemPrompt: { + desc: 'Cấu hình Prompt hệ thống cho Agent với các biến đặt chỗ được xử lý khi chạy.' + } + }, + conversationSettings: { + models: { + chatGroupLabel: 'Mô hình Suy luận / Trò chuyện' + }, + maxRounds: { + desc: 'Số lượt trò chuyện được giữ lại cho ngữ cảnh và viết lại truy vấn' + }, + embeddingTopK: { + desc: 'Số tài liệu giữ lại sau khi truy xuất vector' + }, + keywordThreshold: { + desc: 'Điểm tối thiểu cho truy xuất theo từ khóa' + }, + vectorThreshold: { + desc: 'Độ tương đồng tối thiểu cho truy xuất vector' + }, + rerankTopK: { + desc: 'Số tài liệu giữ lại sau khi Rerank' + }, + rerankThreshold: { + desc: 'Điểm tối thiểu yêu cầu sau khi Rerank' + }, + enableRewrite: { + desc: 'Tự động viết lại truy vấn nhiều lượt để tăng độ bao phủ' + }, + enableQueryExpansion: { + desc: 'Khi độ bao phủ thấp, gọi mô hình suy luận để mở rộng truy vấn (tăng độ trễ & chi phí)' + }, + fallbackStrategy: { + desc: 'Cách phản hồi khi không tìm thấy tài liệu liên quan' + }, + fallbackResponse: { + desc: 'Nội dung trả về khi sử dụng chiến lược dự phòng cố định' + }, + fallbackPrompt: { + desc: 'Prompt sử dụng khi chiến lược dự phòng là "mô hình"' + }, + rewritePrompt: { + desc: 'Prompt hệ thống dùng khi viết lại truy vấn' + }, + chatModel: { + desc: 'Mô hình ngôn ngữ lớn dùng để tóm tắt và tạo nội dung tổng hợp' + }, + rerankModel: { + desc: 'Mô hình Rerank kết quả tìm kiếm (tùy chọn)' + }, + contextTemplate: { + desc: 'Mẫu Prompt để tạo câu trả lời dựa trên kết quả truy xuất ở chế độ chuẩn' + }, + systemPrompt: { + desc: 'Prompt hệ thống cho cuộc trò chuyện ở chế độ chuẩn' + }, + temperature: { + desc: 'Kiểm soát tính ngẫu nhiên của kết quả. 0 là xác định nhất; 1 là ngẫu nhiên nhất' + }, + maxTokens: { + desc: 'Số lượng token tối đa được tạo trong câu trả lời' + } + }, + mcpSettings: { + addUsageInstructions: 'Thêm hướng dẫn sử dụng', + noUsageInstructions: 'Chưa có hướng dẫn sử dụng', + title: 'Dịch vụ MCP', + description: 'Quản lý các dịch vụ MCP (Model Context Protocol) ngoài cho công cụ/tài nguyên ở chế độ Agent', + enabled: 'Đã bật', + disabled: 'Đã tắt', + configuredServices: 'Dịch vụ đã cấu hình', + manageAndTest: 'Quản lý và kiểm tra kết nối dịch vụ MCP', + addService: 'Thêm dịch vụ', + empty: 'Chưa có dịch vụ MCP nào', + actions: { + test: 'Kiểm tra kết nối' + }, + toasts: { + loadFailed: 'Tải danh sách dịch vụ MCP thất bại', + enabled: 'Đã bật dịch vụ MCP', + disabled: 'Đã tắt dịch vụ MCP', + updateStateFailed: 'Cập nhật trạng thái dịch vụ MCP thất bại', + testing: 'Đang kiểm tra {name}...', + noResponse: 'Kiểm tra thất bại: máy chủ không phản hồi', + testFailed: 'Kiểm tra dịch vụ MCP thất bại', + deleted: 'Đã xóa dịch vụ MCP', + deleteFailed: 'Xóa dịch vụ MCP thất bại' + }, + deleteConfirmBody: 'Xóa dịch vụ MCP "{name}"? Thao tác này không thể hoàn tác.', + unnamed: 'Chưa đặt tên', + builtin: 'Tích hợp sẵn', + toolCount: '{count} công cụ', + toolsNotSynced: 'Chưa đồng bộ công cụ', + toolsStale: 'Cần đồng bộ lại' + }, + modelSettings: { + title: 'Cài đặt mô hình', + description: 'Quản lý các loại mô hình AI, bao gồm Ollama cục bộ và API từ xa', + typeShort: { + chat: 'Chat', + embedding: 'Embedding', + rerank: 'Rerank', + vllm: 'Thị giác', + asr: 'Giọng nói' + }, + actions: { + addModel: 'Thêm mô hình', + debugModel: 'Kiểm tra mô hình' + }, + source: { + remote: 'Từ xa', + openaiCompatible: 'Tương thích OpenAI', + custom: 'Tùy chỉnh' + }, + chat: { + title: 'Mô hình Chat', + desc: 'Cấu hình mô hình ngôn ngữ lớn cho hội thoại', + empty: 'Chưa có mô hình chat' + }, + embedding: { + title: 'Mô hình Embedding', + desc: 'Cấu hình mô hình embedding để Embedding văn bản', + empty: 'Chưa có mô hình embedding' + }, + rerank: { + title: 'Mô hình Rerank', + desc: 'Cấu hình mô hình Rerank kết quả tìm kiếm', + empty: 'Chưa có mô hình Rerank' + }, + vllm: { + title: 'Mô hình thị giác VLLM', + desc: 'Cấu hình mô hình thị giác - ngôn ngữ để hiểu đa phương thức', + empty: 'Chưa có mô hình VLLM' + }, + asr: { + title: 'Mô hình giọng nói ASR', + desc: 'Cấu hình mô hình chuyển giọng nói thành văn bản (vd: OpenAI Whisper)', + empty: 'Chưa có mô hình ASR' + }, + toasts: { + nameRequired: 'Tên mô hình không được để trống', + nameTooLong: 'Tên mô hình không được vượt quá 100 ký tự', + displayNameTooLong: 'Tên hiển thị không được vượt quá 100 ký tự', + baseUrlRequired: 'Base URL là bắt buộc đối với API từ xa', + baseUrlInvalid: 'Base URL không hợp lệ, vui lòng kiểm tra lại', + dimensionInvalid: 'Số chiều embedding phải từ 128 đến 4096', + updated: 'Đã cập nhật mô hình', + added: 'Đã thêm mô hình', + saveFailed: 'Lưu mô hình thất bại', + deleted: 'Đã xóa mô hình', + deleteFailed: 'Xóa mô hình thất bại', + builtinCannotEdit: 'Không thể chỉnh sửa mô hình tích hợp sẵn', + builtinCannotDelete: 'Không thể xóa mô hình tích hợp sẵn', + builtinCannotCopy: 'Không thể sao chép mô hình tích hợp sẵn', + copied: 'Đã sao chép mô hình', + copyFailed: 'Sao chép mô hình thất bại' + }, + copySuffix: ' (Bản sao)', + builtinModels: { + title: 'Mô hình tích hợp sẵn', + description: 'Mô hình tích hợp sẵn hiển thị cho tất cả không gian làm việc. Thông tin nhạy cảm được ẩn, không thể chỉnh sửa hoặc xóa.', + descriptionAdmin: 'Mô hình tích hợp sẵn hiển thị cho tất cả không gian làm việc. Quản trị viên hệ thống có thể sửa cấu hình và khóa xác thực; việc xóa do hệ thống triển khai quản lý.', + viewGuide: 'Xem hướng dẫn mô hình tích hợp sẵn' + }, + builtinTag: 'Tích hợp sẵn', + confirmDelete: 'Xóa mô hình "{name}"?', + usage: { + title: 'Không thể xóa mô hình', + description: 'Mô hình "{name}" đang được sử dụng trong các cấu hình sau. Vui lòng chuyển sang mô hình khác trước khi xóa.', + knowledgeBases: 'Kho tri thức ({count})', + agents: 'Agent ({count})', + longTermMemory: 'Bộ nhớ dài hạn', + openConfiguration: 'Mở cài đặt', + truncated: 'Đang hiển thị {shown} trên {total}', + bindings: { + embedding_model: 'Mô hình embedding', + summary_model: 'Mô hình tóm tắt', + image_processing_model: 'Mô hình xử lý ảnh', + vlm_model: 'Mô hình thị giác', + asr_model: 'Mô hình nhận dạng giọng nói', + wiki_synthesis_model: 'Mô hình tổng hợp wiki', + auto_tag_model: 'Mô hình gắn thẻ tự động', + chat_model: 'Mô hình chat', + rerank_model: 'Mô hình Rerank', + query_understand_model: 'Mô hình hiểu truy vấn', + follow_up_model: 'Mô hình gợi ý câu hỏi', + extract_model: 'Mô hình trích xuất bộ nhớ', + unknown: 'Cài đặt mô hình khác' + } + }, + debug: { + reasoningEffort: 'Mức độ suy luận', + reasoningEffortDesc: 'Gửi tham số reasoning_effort theo các mức từ Model Catalog', + title: 'Kiểm tra mô hình', + description: 'Gửi yêu cầu thực tế bằng cấu hình đã lưu. Vui lòng lưu các thay đổi trước khi kiểm tra.', + groupModel: 'Chọn mô hình', + groupInput: 'Dữ liệu kiểm tra', + groupResult: 'Kết quả', + modelType: 'Loại mô hình', + model: 'Mô hình', + modelPlaceholder: 'Chọn mô hình để kiểm tra', + noModelsForType: 'Không có mô hình nào thuộc loại này', + query: 'Đầu vào', + queryPlaceholder: 'Nhập văn bản gửi tới mô hình', + embeddingInput: 'Văn bản cần Embedding', + embeddingPlaceholder: 'Nhập văn bản để tạo embedding', + vlmPrompt: 'Prompt hình ảnh', + vlmPromptPlaceholder: 'Ví dụ: Mô tả chi tiết hình ảnh này', + documents: 'Tài liệu ứng viên', + documentsPlaceholder: 'Nhập mỗi tài liệu trên một dòng', + documentsHint: 'Mỗi dòng có nội dung sẽ được gửi như một tài liệu riêng biệt tới mô hình Rerank', + imageFile: 'Tệp hình ảnh', + audioFile: 'Tệp âm thanh', + chooseFile: 'Chọn tệp', + parameters: 'Tham số yêu cầu', + systemPrompt: 'System Prompt', + systemPromptPlaceholder: 'System prompt tùy chọn', + run: 'Chạy kiểm tra', + copyResult: 'Sao chép kết quả', + history: 'Lịch sử', + runLabel: 'Lần chạy #{n}', + success: 'Yêu cầu thành công', + failed: 'Yêu cầu thất bại', + rawResponse: 'Phản hồi', + requestPreview: 'Xem trước yêu cầu', + requestFailed: 'Yêu cầu kiểm thử mô hình thất bại', + metrics: { + api: 'Giao thức', + thinkingFormat: 'Định dạng suy luận', + requestedReasoningEffort: 'Mức suy luận yêu cầu', + dimension: 'Số chiều', + resultCount: 'Số kết quả', + answerChars: 'Ký tự câu trả lời', + reasoningChars: 'Ký tự suy luận', + reasoningReturned: 'Có kết quả suy luận', + textChars: 'Ký tự văn bản', + segmentCount: 'Số Chunk' + } + } + }, + ollamaSettings: { + title: 'Cài đặt Ollama', + description: 'Quản lý dịch vụ Ollama cục bộ và xem/tải mô hình', + status: { + label: 'Trạng thái dịch vụ Ollama', + desc: 'Tự động kiểm tra dịch vụ Ollama cục bộ. Nếu dịch vụ dừng hoặc sai URL, trạng thái sẽ là "Không khả dụng".', + testing: 'Đang kiểm tra', + available: 'Khả dụng', + unavailable: 'Không khả dụng', + untested: 'Chưa kiểm tra', + retest: 'Kiểm tra lại' + }, + address: { + label: 'URL dịch vụ', + desc: 'Địa chỉ API của Ollama cục bộ, tự động nhận diện. Để thay đổi, hãy cấu hình trong tệp .env.', + placeholder: 'http://localhost:11434', + failed: 'Kết nối thất bại. Vui lòng kiểm tra xem Ollama đã chạy chưa hoặc URL có chính xác không' + }, + download: { + title: 'Tải mô hình', + descPrefix: 'Nhập tên mô hình để tải,', + browse: 'Xem thư viện mô hình Ollama', + placeholder: 'VD: qwen2.5:0.5b', + download: 'Tải về', + downloading: 'Đang tải: {name}' + }, + installed: { + title: 'Mô hình đã cài đặt', + desc: 'Các mô hình đã cài đặt trong Ollama', + empty: 'Chưa có mô hình nào được cài đặt' + }, + toasts: { + connected: 'Kết nối thành công', + connectFailed: 'Kết nối thất bại. Vui lòng kiểm tra xem Ollama đã chạy chưa', + listFailed: 'Không thể lấy danh sách mô hình', + downloadFailed: 'Tải thất bại. Vui lòng thử lại sau', + downloadStarted: 'Đã bắt đầu tải mô hình {name}', + downloadCompleted: 'Tải mô hình {name} thành công', + progressFailed: 'Không thể kiểm tra tiến trình tải' + } + }, + mcpMetadata: { + searchTools: 'Tìm kiếm theo tên hoặc mô tả công cụ', + retry: 'Thử lại', + details: 'Chi tiết', + description: 'Mô tả', + parameters: 'Tham số', + required: 'Bắt buộc', + fullSchema: 'Định nghĩa đầy đủ', + noDescription: 'Không có mô tả', + noParameters: 'Không có định nghĩa tham số', + enabled: 'Đã bật', + approval: 'Yêu cầu phê duyệt', + noTools: 'Không tìm thấy công cụ phù hợp', + next: 'Tiếp tục', + policyLoadFailed: 'Không thể tải chính sách công cụ. Vui lòng thử lại trước khi chỉnh sửa.', + policySaveFailed: 'Không thể lưu cài đặt công cụ', + tools: 'Công cụ', + cacheHint: 'Hệ thống sẽ tự động kết nối nếu chưa lưu danh mục. Các lần truy cập sau chỉ kết nối lại khi bạn làm mới.', + refresh: 'Làm mới công cụ', + fetch: 'Lấy lại dữ liệu', + fetching: 'Đang kết nối và lấy công cụ…', + toolCount: '{count} công cụ', + stale: 'Cấu hình kết nối hoặc xác thực đã thay đổi. Hãy làm mới danh mục cũ này trước khi mô hình sử dụng.', + notSynced: 'Chưa có công cụ nào được đồng bộ. Hãy lấy dữ liệu để lưu mô tả và định nghĩa tham số đầy đủ.', + syncRequired: 'Cần kết nối và lấy công cụ trước. Mô hình chỉ có thể sử dụng danh mục đã đồng bộ.', + needsRefresh: 'Cần làm mới', + saved: 'Danh mục đã lưu', + syncedAt: 'Đồng bộ lần cuối:', + serverDocumentation: 'Tài liệu máy chủ gốc', + noServerDocumentation: 'Kết quả khởi tạo của máy chủ MCP này không chứa instructions hoặc serverInfo.description (cả hai đều không bắt buộc). Mô tả công cụ hiển thị bên dưới.', + policyHint: 'Cài đặt bật/tắt công cụ và phê duyệt được lưu ngay lập tức và giữ nguyên khi làm mới danh mục.', + failed: 'Không thể tải danh mục công cụ', + setupProgress: 'Các bước thiết lập MCP', + connection: 'Kết nối', + toolsAndUsage: 'Công cụ và cách dùng', + previous: 'Quay lại', + usage: 'Cách dùng dịch vụ', + usageHint: 'Mô hình sẽ đọc phần tổng quan này trước khi gọi các công cụ cụ thể. Nội dung sẽ được giữ nguyên khi làm mới.', + summary: 'Tóm tắt cách dùng', + summaryPlaceholder: 'Ví dụ: Tra cứu trạng thái đơn hàng, tiến độ vận chuyển và xử lý hoàn tiền.', + usageInstructions: 'Hướng dẫn sử dụng', + instructionsPlaceholder: 'Mô tả ngắn gọn mục đích, trường hợp sử dụng và các ràng buộc chính.', + generateUsage: 'Tạo bằng AI', + generateHint: 'Tự động tạo hướng dẫn ngắn gọn từ các công cụ đã bật và đồng bộ. Chỉnh sửa và lưu để áp dụng.', + instructionsRequired: 'Vui lòng nhập hướng dẫn sử dụng', + generated: 'Đã tạo xong. Kiểm tra lại và lưu để áp dụng.', + generateFailed: 'Tạo thất bại. Hãy kiểm tra công cụ đã được đồng bộ và mô hình chat đang hoạt động, sau đó thử lại.', + saveNext: 'Lưu và tiếp tục' + }, + mcpServiceDialog: { + addTitle: 'Thêm dịch vụ MCP', + addDesc: 'Kết nối dịch vụ MCP bên ngoài để AI Agent có thể gọi các công cụ tương ứng.', + editTitle: 'Chỉnh sửa dịch vụ MCP', + basicSection: 'Cơ bản', + connectionSection: 'Kết nối', + enableServiceDesc: 'Khi tắt, dịch vụ này sẽ không được gọi', + testAfterSaveHint: 'Lưu cấu hình trước để kiểm tra kết nối', + unitSecond: 'giây', + unitTimes: 'lần', + name: 'Tên dịch vụ', + namePlaceholder: 'Nhập tên dịch vụ', + description: 'Mô tả', + descriptionPlaceholder: 'Nhập mô tả dịch vụ', + transportType: 'Phương thức truyền tải', + serviceUrl: 'URL dịch vụ', + serviceUrlPlaceholder: 'https://example.com/mcp', + enableService: 'Bật dịch vụ', + authConfig: 'Xác thực', + authType: 'Phương thức xác thực', + authTypeNone: 'Không / Header tùy chỉnh', + authTypeApiKey: 'API Key / Token', + authTypeOAuth: 'OAuth 2.0 (ủy quyền khi kết nối lần đầu)', + oauthScopes: 'Scope (tùy chọn, phân tách bằng dấu cách)', + oauthAuthorization: 'Trạng thái ủy quyền', + oauthAuthorized: 'Đã ủy quyền', + oauthRefreshable: 'Token hết hạn; sẽ tự động làm mới ở lần dùng tiếp theo', + oauthUnauthorized: 'Chưa ủy quyền', + oauthAuthorize: 'Ủy quyền', + oauthReauthorize: 'Ủy quyền lại', + oauthRevoke: 'Thu hồi', + oauthAuthorizeHint: 'Nhấp "Ủy quyền" sẽ lưu cấu hình hiện tại trước, sau đó bắt đầu quy trình ủy quyền (mỗi người dùng ủy quyền riêng).', + apiKeyHeader: 'Tên Header', + apiKeyHeaderDesc: 'Mặc định là X-API-Key. Với Bearer, đặt Authorization và nhập "Bearer " bên dưới; với dịch vụ dùng raw token, dùng Authorization cùng token trực tiếp.', + credentialValue: 'Khóa bí mật / Token', + optional: 'Tùy chọn', + advancedConfig: 'Nâng cao', + timeoutSec: 'Thời gian chờ (giây)', + retryCount: 'Số lần thử lại', + retryDelaySec: 'Độ trễ thử lại (giây)', + rules: { + nameRequired: 'Vui lòng nhập tên dịch vụ', + transportRequired: 'Vui lòng chọn phương thức truyền tải', + urlRequired: 'Vui lòng nhập URL dịch vụ', + urlInvalid: 'Vui lòng nhập URL hợp lệ' + }, + toasts: { + created: 'Đã tạo dịch vụ MCP', + updated: 'Đã cập nhật dịch vụ MCP', + createFailed: 'Tạo dịch vụ MCP thất bại', + updateFailed: 'Cập nhật dịch vụ MCP thất bại', + oauthRequired: 'Máy chủ này yêu cầu OAuth. Đã chuyển sang OAuth 2.0 — hãy lưu, sau đó nhấn "Ủy quyền".', + authorized: 'Ủy quyền thành công', + authorizeFailed: 'Không thể bắt đầu ủy quyền', + revoked: 'Đã thu hồi ủy quyền', + revokeFailed: 'Thu hồi ủy quyền thất bại' + }, + customHeaders: { + label: 'Header tùy chỉnh (tùy chọn)', + desc: 'HTTP header gửi kèm mỗi yêu cầu MCP, thường dùng cho xác thực gateway doanh nghiệp, truy vết, v.v.', + add: 'Thêm Header', + keyPlaceholder: 'Tên header', + valuePlaceholder: 'Giá trị header' + }, + codeImport: { + toggle: 'Nhập từ mã cấu hình', + hint: 'Dán JSON cấu hình mcpServers chuẩn để tự động điền biểu mẫu', + parse: 'Phân tích & Điền', + editOverwriteHint: 'Nhập dữ liệu sẽ ghi đè biểu mẫu hiện tại (không ảnh hưởng thông tin xác thực đã lưu; nhấn Lưu để áp dụng)', + errors: { + empty: 'Vui lòng dán cấu hình trước', + invalidJson: 'Không thể phân tích, vui lòng kiểm tra định dạng JSON', + noServer: 'Không tìm thấy cấu hình dịch vụ MCP', + missingUrl: 'Cấu hình thiếu URL', + stdioUnsupported: 'Không hỗ trợ cấu hình stdio (command/args); vui lòng sử dụng cấu hình từ xa có URL' + }, + toasts: { + filled: 'Đã điền biểu mẫu, vui lòng kiểm tra và lưu', + multipleServers: 'Phát hiện nhiều dịch vụ, đã nhập dịch vụ đầu tiên: {name}' + } + } + }, + promptTemplate: { + noTemplates: 'Không có mẫu khả dụng', + selectTemplate: 'Chọn mẫu', + useTemplate: 'Dùng mẫu', + resetDefault: 'Đặt lại mặc định', + default: 'Mặc định', + withKnowledgeBase: 'Kho tri thức', + withWebSearch: 'Tìm kiếm web' + }, + organization: { + title: 'Không gian chia sẻ', + subtitle: 'Tạo hoặc tham gia không gian chia sẻ để nhiều không gian làm việc cùng cộng tác, chia sẻ kho tri thức và agent', + createOrg: 'Tạo không gian chia sẻ', + joinOrg: 'Tham gia không gian chia sẻ', + name: 'Tên không gian chia sẻ', + namePlaceholder: 'Nhập tên không gian chia sẻ', + nameRequired: 'Vui lòng nhập tên không gian chia sẻ', + avatar: 'Ảnh đại diện', + avatarClear: 'Xóa', + avatarPickerHint: 'Chọn một emoji làm ảnh đại diện', + description: 'Mô tả', + descriptionPlaceholder: 'Nhập mô tả không gian chia sẻ (tùy chọn)', + noDescription: 'Không có mô tả', + memberCount: 'Số thành viên', + owner: 'Người tạo', + inviteCode: 'Mã mời', + inviteCodePlaceholder: 'Nhập mã mời', + inviteCodeRequired: 'Vui lòng nhập mã mời', + refreshInviteCode: 'Làm mới mã mời', + inviteCodeRefreshed: 'Đã làm mới mã mời', + inviteCodeRefreshFailed: 'Làm mới mã mời thất bại', + rbac: { + needTenantAdminTip: 'Thao tác này yêu cầu quyền quản trị viên (hoặc cao hơn) trong không gian làm việc hiện tại. Vui lòng liên hệ chủ sở hữu.', + cannotCreate: 'Vai trò hiện tại không đủ quyền để tạo không gian chia sẻ', + cannotJoin: 'Vai trò hiện tại không đủ quyền để tham gia hoặc gửi yêu cầu tham gia không gian chia sẻ', + cannotManage: 'Vai trò hiện tại không đủ quyền để quản lý không gian chia sẻ này' + }, + join: { + title: 'Tham gia không gian chia sẻ', + joining: 'Đang tham gia...', + success: 'Tham gia không gian chia sẻ thành công!', + failed: 'Tham gia không gian chia sẻ thất bại', + noCode: 'Không tìm thấy mã mời', + goToOrganizations: 'Đến Không gian chia sẻ', + confirmTitle: 'Xác nhận tham gia không gian chia sẻ', + confirm: 'Xác nhận tham gia', + preview: 'Xem trước & Tham gia', + memberCount: '{count} thành viên', + shareCount: '{count} kho tri thức chia sẻ', + agentShareCount: '{count} agent', + alreadyMember: 'Bạn đã là thành viên của không gian chia sẻ này', + invalidCode: 'Mã mời không hợp lệ', + byInviteCode: 'Nhập mã mời', + searchSpaces: 'Tìm không gian chia sẻ', + searchSpacesDesc: 'Duyệt hoặc tìm không gian chia sẻ công khai; tham gia không cần mã mời', + searchSpacesPlaceholder: 'Tìm theo tên, mô tả hoặc ID không gian chia sẻ', + spaceId: 'ID không gian chia sẻ', + noSearchResult: 'Không tìm thấy không gian chia sẻ phù hợp', + noSearchableSpaces: 'Chưa có không gian chia sẻ công khai nào, hãy thử tìm kiếm', + memberLimitReached: 'Đã đầy', + backToSearch: 'Quay lại tìm kiếm' + }, + invite: { + loading: 'Đang tải...', + previewTitle: 'Tham gia không gian chia sẻ', + inputDesc: 'Nhập mã mời (hoặc dán từ liên kết mời) để xem và tham gia không gian chia sẻ', + previewAction: 'Xem', + primaryJoin: 'Tham gia', + invalidCode: 'Mã mời không hợp lệ hoặc đã hết hạn', + previewFailed: 'Xem trước thất bại, vui lòng thử lại', + knowledgeBases: 'Kho tri thức', + agents: 'Agent', + alreadyMember: 'Bạn đã là thành viên của không gian chia sẻ này', + submitRequest: 'Gửi yêu cầu tham gia', + requireApprovalTip: 'Không gian chia sẻ này yêu cầu quản trị viên phê duyệt', + approvalLabel: 'Phương thức tham gia', + needApproval: 'Cần phê duyệt', + noApproval: 'Không cần phê duyệt', + defaultRoleAfterJoin: 'Vai trò mặc định sau khi tham gia: {role}', + requestRole: 'Vai trò yêu cầu', + selectRole: 'Chọn vai trò', + messagePlaceholder: 'Không bắt buộc: lời nhắn (ví dụ: giới thiệu hoặc lý do tham gia)', + applicationNote: 'Ghi chú đăng ký (không bắt buộc)', + joinSuccess: 'Tham gia không gian chia sẻ thành công!', + joinFailed: 'Tham gia thất bại, vui lòng thử lại', + requestSubmitted: 'Đã gửi yêu cầu, vui lòng chờ phê duyệt', + requestFailed: 'Gửi yêu cầu thất bại, vui lòng thử lại', + viewOrganization: 'Xem không gian chia sẻ' + }, + leave: 'Rời không gian chia sẻ', + leaveConfirmTitle: 'Rời không gian chia sẻ', + leaveConfirmMessage: 'Bạn có chắc muốn rời không gian chia sẻ "{name}"? Bạn sẽ mất quyền truy cập vào các kho tri thức tại đây.', + leaveSuccess: 'Đã rời không gian chia sẻ', + leaveFailed: 'Rời không gian chia sẻ thất bại', + deleteConfirmTitle: 'Xóa không gian chia sẻ', + deleteConfirmMessage: 'Bạn có chắc muốn xóa không gian chia sẻ "{name}"? Toàn bộ thành viên sẽ bị xóa. Thao tác này không thể hoàn tác.', + deleteSuccess: 'Đã xóa không gian chia sẻ', + deleteFailed: 'Xóa không gian chia sẻ thất bại', + createSuccess: 'Tạo không gian chia sẻ thành công', + createFailed: 'Tạo không gian chia sẻ thất bại', + joinSuccess: 'Tham gia không gian chia sẻ thành công', + joinFailed: 'Tham gia không gian chia sẻ thất bại', + manageMembers: 'Quản lý thành viên', + noMembers: 'Chưa có thành viên', + members: { + listTitle: 'Thành viên không gian chia sẻ', + searchPlaceholder: 'Tìm thành viên…', + loading: 'Đang tải thành viên…', + emptySearch: 'Không có thành viên khớp với "{q}"', + columns: { + member: 'Thành viên', + role: 'Vai trò', + joinedAt: 'Ngày tham gia', + operations: 'Thao tác' + } + }, + joinRequests: { + listTitle: 'Yêu cầu chờ duyệt', + searchPlaceholder: 'Tìm người gửi…', + loading: 'Đang tải yêu cầu…', + emptySearch: 'Không có yêu cầu khớp với "{q}"', + typeJoin: 'Tham gia', + typeUpgrade: 'Nâng cấp', + rejectConfirm: 'Từ chối yêu cầu này?', + approveTitle: 'Duyệt yêu cầu', + approveDesc: 'Chỉ định vai trò cho "{name}" sau khi duyệt', + columns: { + applicant: 'Người yêu cầu', + type: 'Loại', + requestedRole: 'Vai trò yêu cầu', + message: 'Ghi chú', + appliedAt: 'Ngày gửi' + } + }, + sharedResources: { + kbListTitle: 'Kho tri thức đã chia sẻ', + agentListTitle: 'Agent đã chia sẻ', + loading: 'Đang tải…', + columns: { + name: 'Tên', + sharedBy: 'Chia sẻ bởi', + sharedAt: 'Thời gian chia sẻ', + permission: 'Quyền hạn' + } + }, + roleUpdated: 'Đã cập nhật vai trò', + roleUpdateFailed: 'Cập nhật vai trò thất bại', + memberRemoved: 'Đã xóa thành viên', + memberRemoveFailed: 'Xóa thành viên thất bại', + empty: 'Bạn chưa tham gia không gian chia sẻ nào', + emptyDesc: 'Tạo không gian chia sẻ mới hoặc tham gia bằng mã mời', + createdByMe: 'Tôi tạo', + joinedByMe: 'Đã tham gia', + emptyCreated: 'Bạn chưa tạo không gian chia sẻ nào', + emptyCreatedDesc: 'Nhấp "Tạo không gian chia sẻ" để bắt đầu', + emptyJoined: 'Bạn chưa tham gia không gian chia sẻ nào', + emptyJoinedDesc: 'Tham gia không gian chia sẻ bằng mã mời', + role: { + admin: 'Quản trị viên', + editor: 'Chỉnh sửa', + viewer: 'Người xem' + }, + detail: { + removeMemberConfirm: 'Bạn có chắc muốn xóa "{name}"?', + removeMember: 'Xóa thành viên' + }, + settings: { + editTitle: 'Cài đặt không gian chia sẻ', + membersDesc: 'Xem và quản lý thành viên cùng vai trò. Mỗi thành viên đại diện cho một không gian làm việc — mọi người dùng trong đó đều dùng chung quyền truy cập.', + permissionsIconHint: 'Xem quyền của vai trò', + sharedDesc: 'Xem toàn bộ kho tri thức được chia sẻ vào không gian này', + noSharedKB: 'Chưa có kho tri thức được chia sẻ', + noSharedKBTip: 'Chủ sở hữu kho tri thức có thể chia sẻ vào không gian này trong phần Cài đặt kho tri thức', + sharedAgents: 'Agent được chia sẻ', + noSharedAgents: 'Chưa có Agent nào được chia sẻ', + sharedAgentsDesc: 'Các Agent được chia sẻ vào không gian này; thành viên có thể sử dụng khi trò chuyện', + sharedAgentsKbHint: 'Kho tri thức liên kết với Agent chỉ khả dụng (chỉ đọc) khi thành viên dùng Agent đó trong hội thoại (qua {\'@\'}). Chúng không hiển thị trong danh sách Kho tri thức. Để thành viên có thể xem hoặc chỉnh sửa trong danh sách, hãy chia sẻ riêng kho tri thức đó vào không gian này.', + sharedAgentsKbHintShort: 'Kho tri thức liên kết với Agent chỉ đọc trong hội thoại; hãy chia sẻ riêng vào không gian này nếu muốn thành viên thấy hoặc chỉnh sửa trong danh sách.', + noSharedAgentsTip: 'Quản trị viên có thể chia sẻ Agent vào không gian này từ phần cài đặt Agent', + sharePermissionLabel: 'Quyền trong không gian chia sẻ', + myPermissionLabel: 'Quyền hiệu lực', + permissionCalcFormula: 'Quyền trong không gian chia sẻ được thiết lập khi chia sẻ; quyền hiệu lực sẽ lấy mức thấp hơn giữa quyền này và vai trò của bạn trong không gian', + permissionCalcTip: 'Quyền hiệu lực là mức thấp hơn giữa quyền chia sẻ và vai trò của bạn tại đây; người xem chỉ có tối đa quyền đọc kho tri thức này.', + inviteMembers: 'Mời thành viên', + inviteMembersDesc: 'Mời người khác tham gia không gian chia sẻ qua mã hoặc liên kết', + inviteLink: 'Liên kết mời', + inviteLinkValidity: 'Thời hạn liên kết mời', + inviteLinkValidityDesc: 'Thời gian hiệu lực của các liên kết mời mới được tạo', + validity1Day: '1 ngày', + validity7Days: '7 ngày', + validity30Days: '30 ngày', + validityNever: 'Không bao giờ hết hạn', + remainingValidity: 'Hết hạn sau {n} ngày', + remainingValidityNever: 'Không bao giờ hết hạn', + remainingValidityExpired: 'Đã hết hạn', + removeShareFromOrg: 'Xóa khỏi không gian chia sẻ', + removeShareConfirm: 'Xóa "{name}" khỏi không gian chia sẻ này? Thành viên sẽ không còn quyền truy cập vào kho tri thức này.', + removeAgentShareConfirm: 'Xóa "{name}" khỏi không gian chia sẻ này? Thành viên sẽ không còn quyền truy cập vào Agent này.', + removeShareSuccess: 'Đã xóa khỏi không gian chia sẻ', + removeShareFailed: 'Xóa thất bại, vui lòng thử lại', + requireApproval: 'Yêu cầu phê duyệt', + requireApprovalDesc: 'Khi bật, thành viên mới cần quản trị viên phê duyệt để tham gia', + searchable: 'Cho phép tìm kiếm', + searchableDesc: 'Khi bật, không gian này sẽ xuất hiện trong danh sách tìm kiếm "Tham gia không gian chia sẻ"; người khác có thể tìm và yêu cầu tham gia mà không cần mã mời', + memberLimit: 'Giới hạn thành viên', + memberLimitDesc: 'Không thể thêm thành viên mới khi đạt giới hạn; 0 nghĩa là không giới hạn', + memberLimitPlaceholder: '0 = không giới hạn', + memberLimitHint: 'Thành viên hiện tại: {count}', + joinRequests: 'Yêu cầu tham gia', + joinRequestsDesc: 'Xét duyệt các yêu cầu tham gia không gian chia sẻ đang chờ', + noPendingRequests: 'Không có yêu cầu chờ xử lý', + pendingJoinRequestsBadge: 'Yêu cầu tham gia chờ duyệt', + pendingReview: 'Chờ duyệt', + assignRole: 'Chỉ định vai trò', + approve: 'Phê duyệt', + reject: 'Từ chối', + approveSuccess: 'Đã phê duyệt yêu cầu', + rejectSuccess: 'Đã từ chối yêu cầu', + reviewFailed: 'Thao tác thất bại, vui lòng thử lại' + }, + addMember: { + searchTenantPlaceholder: 'Nhập chính xác ID không gian làm việc', + searchTenantHint: 'Tìm theo ID không gian làm việc chính xác, hoặc chia sẻ liên kết mời.', + selectRole: 'Chỉ định vai trò', + confirmBtn: 'Thêm', + success: 'Đã thêm thành viên', + failed: 'Thêm thành viên thất bại', + button: 'Thêm thành viên', + dialogTitle: 'Thêm thành viên', + tipTenant: 'Tư cách thành viên áp dụng ở cấp không gian làm việc: khi một không gian làm việc tham gia, toàn bộ người dùng trong đó sẽ dùng chung quyền truy cập vào không gian này. Kết quả bên dưới được lọc trùng theo không gian làm việc.', + searchTenant: 'ID Không gian làm việc' + }, + share: { + title: 'Chia sẻ vào không gian chung', + selectOrg: 'Chọn không gian chung', + selectOrgPlaceholder: 'Chọn không gian chung để chia sẻ', + permission: 'Quyền truy cập', + permissionTip: 'Quyền chỉnh sửa cho phép sửa đổi nội dung kho tri thức, quyền chỉ đọc chỉ cho phép tìm kiếm và hỏi đáp', + shareSuccess: 'Đã chia sẻ kho tri thức', + shareFailed: 'Chia sẻ thất bại', + unshareSuccess: 'Đã hủy chia sẻ', + unshareFailed: 'Hủy chia sẻ thất bại', + sharedTo: 'Đã chia sẻ với', + noShares: 'Chưa chia sẻ với không gian chung nào', + searchPlaceholder: 'Tìm kiếm không gian chung…', + loading: 'Đang tải…', + emptySearch: 'Không tìm thấy không gian chung khớp với "{q}"', + addShareDialogTitle: 'Chia sẻ vào không gian chung', + unshareAction: 'Dừng chia sẻ', + columns: { + space: 'Không gian chung', + permission: 'Quyền', + sharedAt: 'Thời gian chia sẻ', + operations: 'Thao tác' + }, + sharedKnowledgeBase: 'Kho tri thức được chia sẻ', + agentShareDesc: 'Chia sẻ agent này vào không gian chung để các thành viên có thể sử dụng', + sharedFrom: 'Từ', + permissionReadonly: 'Chỉ đọc', + permissionEditable: 'Chỉnh sửa' + }, + navGroups: { + basic: 'Cơ bản', + management: 'Thành viên & Cộng tác', + resources: 'Tài nguyên chia sẻ' + }, + editor: { + navBasic: 'Thông tin cơ bản', + navPermissions: 'Phân quyền', + navJoin: 'Tham gia không gian chia sẻ', + basicTitle: 'Thông tin cơ bản', + basicDesc: 'Đặt tên và mô tả không gian chia sẻ để dễ nhận diện', + nameTip: 'Nên dùng tên nhóm hoặc dự án để dễ nhận diện', + descriptionTip: 'Mô tả mục đích và định hướng của không gian chia sẻ để các thành viên dễ nắm bắt', + permissionsTitle: 'Quyền thành viên', + permissionsDesc: 'Phạm vi quyền hạn của từng vai trò đối với kho tri thức và Agent trong không gian chia sẻ', + permissionFeature: 'Quyền hạn', + fullAccess: 'Toàn quyền', + editAccess: 'Quyền chỉnh sửa', + viewAccess: 'Chỉ xem', + adminPerm1: 'Quản lý cài đặt không gian chia sẻ, thành viên và việc chia sẻ kho tri thức & Agent', + adminPerm2: 'Chia sẻ và quản lý kho tri thức cùng Agent', + adminPerm3: 'Chỉnh sửa nội dung kho tri thức được chia sẻ', + adminPerm4: 'Xem và tìm kiếm kho tri thức', + useSharedAgentsPerm: 'Sử dụng Agent được chia sẻ', + shareKBPerm: 'Chia sẻ kho tri thức vào không gian chia sẻ', + editorPerm1: 'Chỉnh sửa nội dung kho tri thức được chia sẻ', + editorPerm2: 'Xem và tìm kiếm kho tri thức', + editorPerm3: 'Quản lý cài đặt không gian chia sẻ và thành viên', + viewerPerm1: 'Xem và tìm kiếm kho tri thức', + viewerPerm2: 'Chỉnh sửa nội dung kho tri thức', + viewerPerm3: 'Quản lý cài đặt không gian chia sẻ', + ownerNote: 'Với tư cách là người tạo không gian chia sẻ, bạn sẽ mặc định là quản trị viên với toàn quyền.', + joinTitle: 'Tham gia không gian chia sẻ', + joinDesc: 'Tham gia không gian chia sẻ hiện có bằng mã mời để truy cập kho tri thức và Agent dùng chung', + joinIllustration: 'Nhập mã mời được quản trị viên không gian chia sẻ cung cấp để tham gia', + inviteCodeTip: 'Mã mời do quản trị viên tạo, vui lòng liên hệ họ để nhận mã', + howToGetCode: 'Làm thế nào để lấy mã mời?', + step1: 'Liên hệ với quản trị viên của không gian chia sẻ bạn muốn tham gia', + step2: 'Yêu cầu họ cung cấp mã mời của không gian chia sẻ', + step3: 'Dán mã mời vào ô nhập liệu bên trên' + }, + upgrade: { + requestUpgrade: 'Yêu cầu nâng quyền', + pending: 'Chờ duyệt', + dialogTitle: 'Yêu cầu nâng quyền', + dialogDesc: 'Vai trò của bạn sẽ được cập nhật sau khi quản trị viên phê duyệt.', + currentRole: 'Vai trò hiện tại', + selectRole: 'Vai trò yêu cầu', + reason: 'Lý do (Không bắt buộc)', + reasonPlaceholder: 'Vui lòng nêu ngắn gọn lý do bạn cần quyền hạn cao hơn...', + submitBtn: 'Gửi yêu cầu', + submitSuccess: 'Đã gửi yêu cầu nâng quyền, đang chờ quản trị viên phê duyệt', + submitFailed: 'Gửi yêu cầu thất bại' + } + }, + preview: { + tab: 'Xem trước', + loading: 'Đang tải bản xem trước...', + loadFailed: 'Không thể tải bản xem trước', + retry: 'Thử lại', + unsupported: 'Định dạng tệp không hỗ trợ xem trước trực tuyến', + unsupportedHint: 'Vui lòng tải xuống và mở bằng ứng dụng trên máy', + fullscreen: 'Toàn màn hình', + exitFullscreen: 'Thoát toàn màn hình', + htmlRendered: 'Bản kết xuất', + htmlSource: 'Xem nguồn', + audioLoading: 'Đang tải âm thanh…', + audioNotSupported: 'Trình duyệt không hỗ trợ phát âm thanh', + videoNotSupported: 'Trình duyệt không hỗ trợ phát video', + zoomIn: 'Phóng to', + zoomOut: 'Thu nhỏ' + }, + commandPalette: { + placeholder: 'Tìm kho tri thức, tệp, cuộc trò chuyện…', + clearRecent: 'Xóa', + retrieval: 'Cài đặt truy xuất', + untitledSession: 'Cuộc trò chuyện chưa đặt tên', + scope: { + placeholder: 'Tìm kiếm trong kho tri thức này…', + remove: 'Xóa phạm vi (Backspace)' + }, + group: { + chunks: 'Tệp', + messages: 'Tin nhắn', + kbs: 'Kho tri thức', + agents: 'Agent', + sessionsByTitle: 'Cuộc trò chuyện (theo tiêu đề)', + commands: 'Lệnh', + recent: 'Gần đây', + quickActions: 'Thao tác nhanh' + }, + match: { + vector: 'Vector', + keyword: 'Từ khóa' + }, + quick: { + newChat: 'Cuộc trò chuyện mới', + knowledgeBases: 'Mở kho tri thức', + agents: 'Mở agent', + organizations: 'Mở không gian chung', + settings: 'Mở cài đặt', + productTour: 'Giới thiệu sản phẩm' + }, + empty: { + noResults: 'Không tìm thấy kết quả', + askAi: 'Hỏi trực tiếp AI', + adjustRetrieval: 'Điều chỉnh truy xuất' + }, + hotkey: { + select: 'Điều hướng', + enter: 'Mở', + cmdNumber: 'Chuyển đến', + cmdEnter: 'Bắt đầu chat', + esc: 'Đóng' + } + }, + tools: { + multiKbSearch: 'Tìm kiếm liên kho tri thức', + searchKnowledge: 'Tìm kiếm tri thức', + readDocument: 'Đọc tài liệu', + listDocuments: 'Danh sách tài liệu', + knowledgeSearch: 'Tìm kiếm tri thức', + grepChunks: 'Tìm khớp mẫu văn bản', + getChunkDetail: 'Lấy chi tiết Chunk', + listKnowledgeChunks: 'Danh sách Chunk tri thức', + listKnowledgeBases: 'Danh sách kho tri thức', + getDocumentInfo: 'Lấy thông tin tài liệu', + queryKnowledgeGraph: 'Truy vấn đồ thị tri thức', + think: 'Suy luận sâu', + todoWrite: 'Lập kế hoạch' + }, + vectorStoreBadge: { + systemDefault: 'Mặc định hệ thống', + sharedFromOrg: 'Chia sẻ từ tổ chức khác', + unknownStore: 'Bộ lưu trữ không xác định', + unavailable: 'Không khả dụng' + }, + kbSettings: { + vectorStore: { + title: 'Bộ lưu trữ Vector', + description: 'Chọn bộ lưu trữ vector ghi dữ liệu cho kho tri thức này. Liên kết này là vĩnh viễn — để chuyển sang bộ lưu trữ khác, hãy tạo kho tri thức mới và đánh chỉ mục lại.', + loading: 'Đang tải bộ lưu trữ vector...', + engineLabel: 'Bộ lưu trữ vector', + engineDesc: 'Chọn một bộ lưu trữ từ cấu hình toàn cục, hoặc để Mặc định hệ thống để dùng RETRIEVE_DRIVER của không gian làm việc.', + boundLabel: 'Bộ lưu trữ vector đã liên kết', + systemDefault: 'Mặc định hệ thống', + immutableHint: 'Không thể thay đổi sau khi tạo. Để chuyển đổi, hãy tạo kho tri thức mới liên kết với bộ lưu trữ mong muốn và đánh chỉ mục lại.', + immutableEdit: 'Không thể thay đổi liên kết bộ lưu trữ vector sau khi tạo.', + unavailableHint: 'Vector Store liên kết hiện không khả dụng; kiểm tra cấu hình kết nối tại Cài đặt → Vector Store.', + goGlobalSettings: 'Đi tới Cài đặt Vector Store' + }, + storage: { + title: 'Bộ lưu trữ', + selectDescription: 'Chọn phiên bản lưu trữ cụ thể để liên kết với kho tri thức này.', + defaultTag: 'Mặc định', + instanceLabel: 'Phiên bản lưu trữ', + instanceDesc: 'Cùng một loại lưu trữ có thể có nhiều phiên bản với endpoint, bucket hoặc thông tin xác thực khác nhau.', + migrateHint: 'Kho tri thức này đã chứa tệp; sử dụng quy trình chuyển đổi lưu trữ để đổi phiên bản.', + manageInstances: 'Quản lý phiên bản lưu trữ', + localStorage: 'Lưu trữ cục bộ', + loading: 'Đang tải...' + }, + parser: { + title: 'Công cụ phân tích', + description: 'Chọn công cụ phân tích tài liệu cho từng loại tệp. Các loại tệp chưa cấu hình sẽ dùng công cụ tích hợp sẵn.', + loading: 'Đang tải...', + noEngineAvailable: 'Không có công cụ phân tích khả dụng hoặc dịch vụ phân tích tài liệu chưa được cấu hình.', + default: 'Mặc định', + goConfig: 'Đến Cấu hình →', + noEngine: 'Không có công cụ khả dụng', + fileTypePdf: 'Tài liệu PDF', + fileTypeWord: 'Tài liệu Word', + fileTypePpt: 'Bản trình chiếu', + fileTypeExcel: 'Bảng tính Excel', + xlsxFirstRowAsHeader: 'Dùng hàng đầu tiên làm ngữ cảnh cột cho từng hàng', + fileTypeEbook: 'Sách điện tử', + fileTypeWebArchive: 'Bản lưu trữ web', + fileTypeCsv: 'Tệp CSV', + fileTypeText: 'Văn bản thuần', + fileTypeJson: 'Tệp JSON', + fileTypeImage: 'Hình ảnh', + fileTypeAudiovisual: 'Âm thanh', + engines: { + builtin: { + name: 'Tích hợp sẵn', + desc: 'Công cụ phân tích DocReader tích hợp (docx/pdf/xlsx và các định dạng phức tạp khác)' + }, + simple: { + name: 'Đơn giản', + desc: 'Phân tích hình ảnh & định dạng đơn giản (không cần dịch vụ bên ngoài)' + }, + anydoc: { + name: 'anydoc', + desc: 'Bộ phân tích tài liệu văn phòng trực tiếp (không cần dịch vụ bên ngoài)' + }, + mineru: { + name: 'MinerU', + desc: 'Dịch vụ MinerU tự lưu trữ' + }, + mineru_cloud: { + name: 'MinerU Cloud', + desc: 'API MinerU Cloud' + }, + paddleocr_vl: { + name: 'PaddleOCR-VL', + desc: 'Dịch vụ PaddleOCR-VL tự lưu trữ' + }, + paddleocr_vl_cloud: { + name: 'PaddleOCR-VL Cloud', + desc: 'API PaddleOCR-VL Cloud' + }, + weknoracloud: { + name: 'WeKnora Cloud', + desc: 'Phân tích tài liệu qua WeKnora Cloud' + }, + markitdown: { + name: 'MarkItDown', + desc: 'Bộ chuyển đổi Microsoft MarkItDown (PDF/Office/HTML và định dạng khác)' + }, + opendataloader: { + name: 'OpenDataLoader', + desc: 'Bộ phân tích PDF OpenDataLoader (phân tích bố cục; yêu cầu Java 11+ và opendataloader-pdf)' + } + } + } + }, + agentStream: { + toolApproval: { + waiting: 'Chờ duyệt · {target}', + waitingStatus: 'Chờ duyệt', + targetWithTool: '{service} › {tool}', + titleWithTarget: 'Duyệt · {service} › {tool}', + argsLabel: 'Tham số', + argsModified: 'Đã chỉnh sửa', + countdownShort: '{seconds}s', + approve: 'Duyệt & chạy', + reject: 'Từ chối', + approvedTag: 'Đã duyệt', + rejectedTag: 'Đã từ chối', + invalidJson: 'Tham số phải là JSON hợp lệ', + submitted: 'Đã gửi', + submitFailed: 'Gửi thất bại', + userRejected: 'Người dùng đã từ chối' + }, + mcpOAuth: { + waiting: 'Chờ ủy quyền · {target}', + waitingStatus: 'Chờ ủy quyền', + targetWithTool: '{service} › {tool}', + titleWithService: 'OAuth · {service}', + titleWithTool: 'OAuth · {service} › {tool}', + desc: 'Quá trình ủy quyền sẽ mở cửa sổ mới để đăng nhập. Công cụ sẽ tự động tiếp tục sau khi ủy quyền thành công.', + authorize: 'Ủy quyền', + skip: 'Bỏ qua', + countdownShort: '{seconds}s', + authorizedTag: 'Đã ủy quyền', + timedOutTag: 'Hết thời gian ủy quyền', + canceledTag: 'Đã hủy', + authorizedToast: 'Đã ủy quyền. Đang tiếp tục…', + startFailed: 'Không thể bắt đầu ủy quyền', + resumeFailed: 'Không thể tiếp tục. Vui lòng thử lại.', + skipFailed: 'Không thể bỏ qua. Vui lòng thử lại.' + }, + tools: { + searchKnowledge: 'Tìm kiếm kho tri thức', + grepChunks: 'Tìm kiếm mẫu văn bản', + webSearch: 'Tìm kiếm web', + webFetch: 'Tải nội dung web', + getDocumentInfo: 'Lấy thông tin tài liệu', + listKnowledgeChunks: 'Danh sách Chunk tri thức', + getRelatedDocuments: 'Tìm tài liệu liên quan', + getDocumentContent: 'Lấy nội dung tài liệu', + wikiReadSourceDoc: 'Đọc sâu tài liệu gốc', + readDocument: 'Đọc tài liệu', + listDocuments: 'Danh sách tài liệu', + todoWrite: 'Quản lý kế hoạch', + knowledgeGraphExtract: 'Trích xuất đồ thị tri thức', + thinking: 'Đang suy luận', + attachmentParsing: 'Phân tích tệp đính kèm', + imageAnalysis: 'Phân tích hình ảnh', + queryUnderstand: 'Phân tích truy vấn', + queryKnowledgeGraph: 'Truy vấn đồ thị tri thức', + readSkill: 'Đọc kỹ năng', + executeSkillScript: 'Chạy script kỹ năng', + listSandboxFiles: 'Danh sách tệp Sandbox', + readFile: 'Đọc tệp', + readSandboxFile: 'Đọc tệp Sandbox', + writeSandboxFile: 'Ghi tệp Sandbox', + editSandboxFile: 'Sửa tệp Sandbox', + shellExec: 'Chạy lệnh Sandbox', + dataAnalysis: 'Phân tích dữ liệu', + dataSchema: 'Cấu trúc dữ liệu', + databaseQuery: 'Truy vấn cơ sở dữ liệu' + }, + skillFiles: { + heading: 'Tệp kỹ năng', + script: 'script', + instructions: 'Hướng dẫn' + }, + sandboxFiles: { + found: 'Tìm thấy {count} tệp', + empty: 'Không có tệp', + truncated: 'Danh sách đã bị rút gọn', + wrote: 'Đã ghi', + edited: 'Đã sửa', + replacements: 'Đã thay thế {count}', + moreLines: 'Thêm {count} dòng' + }, + shellExec: { + workDir: 'Thư mục', + exitCode: 'Mã thoát', + stdout: 'Stdout', + stderr: 'Stderr', + emptyOutput: 'Không có kết quả', + truncated: 'Đầu ra đã bị rút gọn', + killed: 'Hết thời gian chờ', + binarySuppressed: 'Đã ẩn đầu ra nhị phân. Hãy ghi tệp vào thư mục Artifacts để tải xuống.' + }, + citation: { + notFound: 'Không tìm thấy nội dung', + loadFailed: 'Tải thất bại', + noKbForWiki: 'Không xác định được kho tri thức liên kết. Không thể mở Wiki.' + }, + toolSummary: { + getDocument: 'Lấy tài liệu: {title}', + document: 'Tài liệu', + listChunks: 'Xem {title}', + listFaqEntry: 'Xem FAQ: {question}', + deepThinking: 'Suy luận sâu' + }, + plan: { + inProgress: 'Đang xử lý', + pending: 'Chờ xử lý', + completed: 'Đã hoàn thành' + }, + search: { + noResults: 'Không tìm thấy nội dung phù hợp', + candidatesBelowThreshold: 'Khớp {count} kết quả, nhưng không đủ liên quan để sử dụng', + foundResultsFromFiles: 'Tìm thấy {count} kết quả từ {files} tệp', + foundResults: 'Tìm thấy {count} kết quả', + foundMixedResults: 'Tìm thấy {count} kết quả ({docCount} tài liệu, {webCount} kết quả web)', + webResults: 'Tìm thấy {count} kết quả web', + grepSummary: 'Tìm thấy {chunks} Chunk khớp trong {docs} tài liệu' + }, + grepResults: { + chunkHits: '{count} Chunk', + keywordHits: '{count} kết quả', + titleMatch: 'tiêu đề', + faqEntry: 'Mục FAQ' + }, + knowledgeChunksList: { + chunkRange: 'Đã tải {fetched} / {total} Chunk', + page: 'Trang {page}, {pageSize} mục/trang', + offsetRange: 'Chunk {from}–{to}', + queryMatches: '{count} kết quả khớp với "{query}" trong tài liệu này', + queryNoMatch: 'Không có kết quả khớp với "{query}" trong tài liệu này' + }, + attachmentParsing: { + parsedSummary: 'Đã phân tích {count} tệp đính kèm', + parsedWithSkipped: 'Đã phân tích {parsed} tệp đính kèm, bỏ qua {skipped} (đang xử lý)', + noneReady: 'Không có tệp đính kèm khả dụng' + }, + ragPipeline: { + searching: 'Đang tìm kiếm kho tri thức...', + searchingWithQuery: 'Đang tìm kiếm kho tri thức: "{query}"', + searchingWeb: 'Đang tìm kiếm web...', + searchingWebWithQuery: 'Đang tìm kiếm web: "{query}"', + searchingMixed: 'Đang tìm kiếm kho tri thức và web...', + searchingMixedWithQuery: 'Đang tìm kiếm kho tri thức và web: "{query}"', + searchDone: 'Tìm kiếm hoàn tất' + }, + mcp: { + discoverTools: 'Khám phá công cụ MCP', + listServers: 'Danh sách dịch vụ MCP', + listTools: 'Danh sách công cụ MCP', + searchTools: 'Tìm kiếm công cụ MCP', + describeTool: 'Xem định nghĩa công cụ', + callTool: 'Gọi công cụ MCP', + showing: 'Hiển thị {count} trên {total}', + moreAvailable: 'Còn kết quả khác', + empty: 'Không có nội dung', + parameters: 'Tham số', + expand: 'Xem thêm', + collapse: 'Thu gọn', + required: 'Bắt buộc', + fullSchema: 'Định nghĩa tham số chi tiết', + failed: 'Thao tác MCP thất bại', + result: 'Kết quả', + status: { + not_loaded: 'Chưa tải', + loading: 'Đang tải', + ready: 'Sẵn sàng', + needs_auth: 'Yêu cầu xác thực', + error: 'Lỗi kết nối', + disabled: 'Đã tắt', + unavailable: 'Không khả dụng' + } + }, + toolStatus: { + calling: 'Đang gọi {name}...', + searchKb: 'Tìm kiếm kho tri thức', + searchKbFailed: 'Tìm kiếm kho tri thức thất bại', + searchMixed: 'Tìm kiếm kho tri thức và web', + searchMixedFailed: 'Tìm kiếm thất bại', + webSearch: 'Tìm kiếm web', + webSearchFailed: 'Tìm kiếm web thất bại', + grepSearch: 'Tìm kiếm từ khóa', + grepSearchFailed: 'Tìm kiếm từ khóa thất bại', + getDocInfo: 'Lấy thông tin tài liệu', + getDocInfoFailed: 'Lấy thông tin tài liệu thất bại', + viewDocument: 'Xem tài liệu', + thinkingDone: 'Suy luận hoàn tất', + thinkingFailed: 'Suy luận thất bại', + updateTodos: 'Đang cập nhật danh sách việc cần làm', + updateTodosFailed: 'Cập nhật danh sách việc cần làm thất bại', + imageAnalyzing: 'Đang đọc nội dung hình ảnh...', + imageAnalysisDone: 'Đã đọc nội dung hình ảnh', + imageAnalysisFailed: 'Đọc hình ảnh thất bại', + attachmentParsing: 'Đang xử lý tệp đính kèm...', + attachmentParsingDone: 'Đã xử lý tệp đính kèm', + attachmentParsingFailed: 'Xử lý tệp đính kèm thất bại', + queryUnderstanding: 'Đang phân tích truy vấn...', + queryUnderstandDone: 'Đã phân tích truy vấn', + called: 'Đã gọi {name}', + calledFailed: 'Gọi {name} thất bại', + shellExecRunning: 'Đang chạy lệnh trong Sandbox...' + }, + copy: { + emptyContent: 'Nội dung phản hồi trống, không thể sao chép', + success: 'Đã sao chép vào khay nhớ tạm', + failed: 'Sao chép thất bại, vui lòng sao chép thủ công' + }, + saveToKb: { + emptyContent: 'Nội dung phản hồi trống, không thể lưu vào kho tri thức', + editorOpened: 'Đã mở trình chỉnh sửa, vui lòng chọn kho tri thức để lưu' + } + }, + agentEditor: { + builtinHint: 'Đây là Agent tích hợp sẵn. Không thể sửa tên và mô tả, nhưng có thể điều chỉnh các tham số cấu hình.', + navGroups: { + basic: 'Cơ bản', + knowledge: 'Tri thức & Truy xuất', + capability: 'Mở rộng', + integration: 'Xuất bản & Tích hợp' + }, + questionSuggestions: { + navLabel: 'Gợi ý câu hỏi', + title: 'Gợi ý câu hỏi hội thoại', + description: 'Cấu hình câu hỏi mở đầu và gợi ý tiếp theo trong một chính sách duy nhất của Agent. Kênh có thể ẩn nhưng không thể ghi đè chính sách này.', + startersTitle: 'Câu hỏi mở đầu', + followUpsTitle: 'Gợi ý sau câu trả lời', + enableStarters: 'Hiển thị câu hỏi mở đầu', + enableStartersDesc: 'Hiển thị trước tin nhắn đầu tiên từ nguồn biên soạn sẵn, kho tri thức hoặc kết hợp.', + enableFollowUps: 'Tạo câu hỏi gợi ý tiếp theo', + enableFollowUpsDesc: 'Tạo bất đồng bộ sau mỗi câu trả lời hoàn tất. Bật tính năng này sẽ tăng mức sử dụng mô hình.', + sourceMode: 'Chế độ nguồn', + count: 'Số lượng câu hỏi', + curatedItems: 'Câu hỏi biên soạn sẵn', + curatedItemsDesc: 'Dùng cho câu hỏi mở đầu và được ưu tiên trong chế độ kết hợp.', + addItem: 'Thêm câu hỏi', + model: 'Mô hình sinh gợi ý', + modelDesc: 'Để trống để dùng mô hình của lượt hội thoại vừa hoàn tất.', + advancedSettings: 'Cài đặt sinh nâng cao', + displayRules: 'Quy tắc hiển thị và dự phòng', + contextTurns: 'Số lượt ngữ cảnh', + categories: 'Loại câu hỏi', + instruction: 'Chỉ dẫn bổ sung', + instructionPlaceholder: 'Ví dụ: ưu tiên câu hỏi hành động tiếp theo, tránh câu hỏi quá chung chung hoặc lặp lại câu trả lời…', + suppressFallback: 'Ẩn sau các câu trả lời dự phòng', + suppressQuestion: 'Ẩn khi câu trả lời kết thúc bằng một câu hỏi', + knowledgeFallback: 'Dùng câu hỏi từ tri thức nếu sinh tự động thất bại', + allowRegenerate: 'Cho phép người dùng tạo lại', + modeCurated: 'Biên soạn sẵn', + modeKnowledge: 'Từ tri thức', + modeGenerated: 'Sinh tự động', + modeHybrid: 'Kết hợp', + categoryClarify: 'Làm rõ', + categoryDeepen: 'Đào sâu', + categoryAction: 'Bước tiếp theo' + }, + placeholders: { + available: 'Biến khả dụng: ', + clickToInsert: '(nhấp để chèn)', + hint: '(nhấp để chèn hoặc nhập {\'{{\'} để hiển thị danh sách)' + }, + intentPrompts: { + title: 'Prompt theo ý định', + sectionDesc: 'Cấu hình prompt hệ thống cho từng ý định cụ thể; mặc định sẽ được áp dụng nếu không tùy chỉnh', + intentLabel: 'Ý định', + promptPlaceholder: 'Nhập prompt hệ thống tùy chỉnh...', + customized: 'Đã tùy chỉnh', + empty: 'Không có mẫu ý định nào' + }, + promptNav: { + ariaLabel: 'Bố cục prompt', + system: 'Prompt hệ thống', + context: 'Mẫu ngữ cảnh', + intent: 'Prompt theo ý định', + rewriteSystem: 'Viết lại · Hệ thống', + rewriteUser: 'Viết lại · Người dùng', + fallback: 'Dự phòng truy xuất' + }, + selection: { + all: 'Tất cả', + selected: 'Đã chọn', + disabled: 'Đã tắt' + }, + desc: { + name: 'Đặt tên dễ nhận biết cho Agent', + description: 'Mô tả ngắn gọn mục đích và tính năng của Agent', + systemPrompt: 'Prompt hệ thống tùy chỉnh để xác định hành vi và vai trò của Agent', + promptInheritance: 'Nội dung mẫu chưa chỉnh sửa sẽ tự động cập nhật theo bản cập nhật của mẫu; văn bản đã sửa sẽ được lưu thành prompt tùy chỉnh. Trong chế độ Agent, trường này định nghĩa vai trò và quy trình làm việc; quyền hạn công cụ và nguồn chọn cho từng lượt được kiểm soát riêng biệt.', + leaveEmptyDefault: '(để trống để dùng mặc định hệ thống)', + contextTemplate: 'Định dạng nội dung truy xuất trước khi đưa vào mô hình', + model: 'Chọn LLM mà Agent sử dụng', + temperature: 'Kiểm soát độ ngẫu nhiên của đầu ra: 0 là tất định nhất, 1 là ngẫu nhiên nhất', + maxTokens: 'Số token tối đa cho câu trả lời của mô hình. Mặc định là 2048. Giá trị tùy chỉnh được lưu đúng như đã nhập.', + maxTokensAgent: 'Số token tối đa sinh ra trong mỗi vòng suy luận, bao gồm JSON gọi công cụ. Mặc định là 4096 khi không có Sandbox, hoặc 24576 khi Sandbox có quyền ghi hoặc sửa tệp. Giá trị tùy chỉnh được lưu đúng như đã nhập và không bị thay đổi sau đó.', + thinking: 'Bật khả năng suy luận mở rộng (yêu cầu mô hình hỗ trợ)', + conversationSection: 'Cấu hình hội thoại nhiều lượt và tham số viết lại truy vấn', + conversationSectionAgent: 'Suy luận thông minh luôn ở chế độ nhiều lượt. Hội thoại trước đó được giữ tối đa theo Context Window của mô hình, các lượt cũ hơn sẽ tự động được tóm tắt khi Context Window bị đầy', + multiTurn: 'Khi bật, ngữ cảnh lịch sử hội thoại sẽ được lưu giữ', + historyRounds: 'Số lượt hội thoại gần nhất được giữ làm ngữ cảnh', + retainRetrievalHistory: 'Giữ lại kết quả kho tri thức từ các lượt trước. Khi tắt, mỗi lượt sẽ tìm kiếm lại', + rewrite: 'Tự động viết lại câu hỏi người dùng trong hội thoại nhiều lượt để làm rõ đại từ và nội dung lược bỏ', + memoryEnabled: 'Cho phép Agent đọc và ghi vào bộ nhớ dài hạn của bạn. Khi tắt, cuộc trò chuyện với Agent sẽ không đọc hay thêm bộ nhớ mới. Bật tùy chọn này không có tác dụng nếu công tắc ở cấp cá nhân hoặc không gian làm việc đang tắt', + queryUnderstandModel: 'Mô hình dùng để phân tích truy vấn (viết lại và nhận diện ý định). Để trống để dùng lại mô hình trò chuyện chính.', + rewriteSystemPrompt: 'Prompt hệ thống để viết lại câu hỏi (để trống để dùng mặc định)', + rewriteUserPrompt: 'Mẫu prompt người dùng để viết lại câu hỏi (để trống để dùng mặc định)', + selectTools: 'Chọn các công cụ khả dụng cho Agent', + maxIterations: 'Giới hạn số bước suy luận tối đa cho một tác vụ. Không giới hạn sẽ tiếp tục cho đến khi mô hình tự dừng hoặc bạn dừng lại.', + kbScope: 'Chọn phạm vi kho tri thức agent có thể truy cập', + webSearch: 'Cho phép agent tìm kiếm thông tin trên internet', + webSearchProvider: 'Chỉ định công cụ tìm kiếm cho agent này. Để trống để dùng mặc định.', + webSearchMaxResults: 'Số lượng kết quả tối đa cho mỗi lượt tìm kiếm', + webFetchEnabled: 'Tự động tải nội dung đầy đủ từ các kết quả web hàng đầu sau khi Rerank để trả lời tốt hơn', + webFetchTopN: 'Số lượng trang web tối đa cần tải sau khi Rerank', + retrievalSection: 'Cấu hình truy xuất kho tri thức, xếp hạng và chiến lược ưu tiên FAQ', + queryExpansion: 'Tự động mở rộng từ khóa truy vấn để tăng độ phủ tìm kiếm', + embeddingTopK: 'Số kết quả tối đa từ truy xuất vector', + keywordThreshold: 'Điểm liên quan tối thiểu cho truy xuất từ khóa', + vectorThreshold: 'Điểm tương đồng tối thiểu cho truy xuất vector', + rerankTopK: 'Số kết quả tối đa giữ lại sau khi Rerank', + rerankThreshold: 'Điểm liên quan tối thiểu khi Rerank', + fallbackStrategy: 'Cách xử lý khi không tìm thấy nội dung liên quan trong kho tri thức', + fallbackResponse: 'Văn bản cố định trả về khi không thể trả lời', + fallbackPrompt: 'Prompt điều hướng phản hồi của mô hình khi không tìm thấy câu trả lời trong kho tri thức' + }, + tools: { + thinking: 'Tư duy', + thinkingDesc: 'Công cụ tư duy phản biện và giải quyết vấn đề linh hoạt', + todoWrite: 'Lập kế hoạch', + todoWriteDesc: 'Tạo kế hoạch nghiên cứu có cấu trúc', + searchKnowledge: 'Tìm kiếm tri thức', + searchKnowledgeDesc: 'Tìm kiếm ngữ nghĩa, từ khóa hoặc kết hợp trên các Chunk kho tri thức', + readDocument: 'Đọc tài liệu', + readDocumentDesc: 'Đọc siêu dữ liệu và Chunk tài liệu, hỗ trợ phân trang và tìm kiếm trong tài liệu', + listDocuments: 'Danh sách tài liệu', + listDocumentsDesc: 'Duyệt danh sách tài liệu trong kho tri thức theo trang', + grepChunks: 'Tìm kiếm từ khóa', + grepChunksDesc: 'Định vị nhanh tài liệu và Chunk chứa từ khóa cụ thể', + knowledgeSearch: 'Tìm kiếm ngữ nghĩa', + knowledgeSearchDesc: 'Hiểu câu hỏi và tìm kiếm nội dung liên quan theo ngữ nghĩa', + listChunks: 'Xem Chunk', + listChunksDesc: 'Lấy toàn bộ nội dung Chunk của một tài liệu', + queryGraph: 'Truy vấn đồ thị tri thức', + queryGraphDesc: 'Truy vấn các mối quan hệ từ đồ thị tri thức', + getDocInfo: 'Thông tin tài liệu', + getDocInfoDesc: 'Xem siêu dữ liệu của tài liệu', + dbQuery: 'Truy vấn cơ sở dữ liệu', + dbQueryDesc: 'Truy vấn dữ liệu từ cơ sở dữ liệu', + dataAnalysis: 'Phân tích dữ liệu', + dataAnalysisDesc: 'Đọc hiểu tệp dữ liệu và thực hiện phân tích', + dataSchema: 'Xem cấu trúc dữ liệu', + dataSchemaDesc: 'Lấy siêu dữ liệu của các tệp dạng bảng', + requiresKb: '(yêu cầu cấu hình kho tri thức)', + requiresRagKb: '(yêu cầu kho tri thức đã bật lập chỉ mục vector/từ khóa)', + requiresWikiKb: '(yêu cầu kho tri thức đã bật Wiki)', + wikiSearch: 'Tìm kiếm Wiki', + wikiSearchDesc: 'Tìm kiếm từ khóa / ngữ nghĩa trên các trang Wiki', + wikiReadPage: 'Đọc trang Wiki', + wikiReadPageDesc: 'Đọc toàn bộ nội dung của một trang Wiki cụ thể', + wikiReadSourceDoc: 'Đọc tài liệu nguồn', + wikiReadSourceDocDesc: 'Đọc sâu các tài liệu gốc tạo nên trang Wiki', + wikiFlagIssue: 'Báo cáo vấn đề Wiki', + wikiFlagIssueDesc: 'Báo cáo sai lệch dữ kiện hoặc xung đột hợp nhất trên trang Wiki', + wikiWritePage: 'Tạo / Ghi đè Wiki', + wikiWritePageDesc: 'Tạo trang mới hoặc ghi đè hoàn toàn trang hiện có', + wikiReplaceText: 'Thay thế văn bản Wiki', + wikiReplaceTextDesc: 'Thay thế đoạn văn bản cụ thể trong trang Wiki', + wikiRenamePage: 'Đổi tên trang Wiki', + wikiRenamePageDesc: 'Đổi tên trang Wiki và tự động cập nhật các liên kết chéo', + wikiDeletePage: 'Xóa trang Wiki', + wikiDeletePageDesc: 'Xóa trang Wiki và dọn dẹp các liên kết hỏng', + wikiReadIssue: 'Xem vấn đề Wiki', + wikiReadIssueDesc: 'Xem chi tiết vấn đề trên trang Wiki', + wikiUpdateIssue: 'Cập nhật vấn đề Wiki', + wikiUpdateIssueDesc: 'Cập nhật trạng thái vấn đề của trang Wiki', + webSearch: 'Tìm kiếm Web', + webFetch: 'Tải trang Web', + groupBase: 'Cơ bản', + groupRag: 'Truy xuất tri thức (RAG)', + groupWikiRead: 'Đọc Wiki', + groupWikiEdit: 'Chỉnh sửa Wiki', + groupWikiIssue: 'Đánh giá Wiki', + groupData: 'Phân tích dữ liệu', + writeWarning: 'Làm thay đổi nội dung Wiki', + dangerTag: 'Ghi', + statusNoKb: 'Chưa liên kết kho tri thức', + kbMetricRag: 'Kho RAG', + kbMetricWiki: 'Kho Wiki', + statusInactive: '{count} công cụ đã chọn không thể hoạt động với cấu hình hiện tại', + effectiveLabel: 'Công cụ khả dụng', + effectiveDesc: 'Được xác định theo cấu hình hiện tại — đây là các công cụ agent thực tế có thể gọi', + effectiveEmpty: 'Không có công cụ khả dụng — agent sẽ trở về chế độ trò chuyện thông thường' + }, + embed: { + title: 'Nhúng trang web', + description: 'Nhúng agent này vào website để khách truy cập có thể chat qua cửa sổ nội trang hoặc nút bấm nổi. Phạm vi tri thức kế thừa từ agent này.' + }, + im: { + title: 'Tích hợp ứng dụng nhắn tin', + description: 'Kết nối agent với các nền tảng nhắn tin như WeCom, Feishu, Lark, Slack, Telegram, DingTalk, Mattermost, WeChat, QQBot và Yunzhijia', + feishu: 'Feishu', + lark: 'Lark', + slack: 'Slack', + telegram: 'Telegram', + dingtalk: 'DingTalk', + mattermost: 'Mattermost', + wecom: 'WeCom', + wechat: 'WeChat', + qqbot: 'QQBot', + yunzhijia: 'Yunzhijia', + addChannel: 'Thêm kênh', + channelsTitle: 'Kênh nhắn tin', + disabled: 'Đã tắt', + editChannel: 'Chỉnh sửa kênh', + deleteConfirm: 'Bạn có chắc chắn muốn xóa kênh này không? Hành động này không thể hoàn tác.', + channelName: 'Tên kênh', + channelNamePlaceholder: 'Nhập tên để dễ nhận biết', + channelNameDefaultHint: 'Mặc định theo tên nền tảng; bạn có thể tùy chỉnh hoặc để trống để tự động áp dụng khi lưu', + platform: 'Nền tảng', + mode: 'Chế độ kết nối', + outputMode: 'Chế độ phản hồi', + outputStream: 'Truyền phát (Streaming)', + outputFull: 'Phản hồi đầy đủ', + callbackUrl: 'URL Callback', + empty: 'Chưa có kênh IM nào', + unnamed: 'Kênh chưa đặt tên', + docLink: 'Hướng dẫn tích hợp', + wecomConsole: 'Trang quản trị WeCom', + feishuConsole: 'Nền tảng mở Feishu', + larkConsole: 'Nền tảng mở Lark', + slackConsole: 'Bảng điều khiển Slack API', + telegramConsole: 'BotFather Telegram', + dingtalkConsole: 'Nền tảng mở DingTalk', + dingtalkCardTemplateId: 'ID mẫu thẻ (tùy chọn)', + dingtalkCardTemplateIdHint: 'Tạo mẫu AI Card tại open-dev.dingtalk.com/fe/card để bật phản hồi dạng luồng với hiệu ứng máy đánh chữ', + mattermostConsole: 'Tích hợp Mattermost', + qqbotConsole: 'Nền tảng mở QQ', + qqbotAPIBaseURLHint: 'Tùy chọn. Để trống để dùng endpoint API production mặc định.', + qqbotGatewayURLHint: 'Tùy chọn. Để trống để tự động lấy WebSocket gateway mặc định.', + yunzhijiaConsole: 'Nền tảng mở Yunzhijia', + yunzhijiaRobotDoc: 'Tài liệu tin nhắn Robot', + yunzhijiaImageDoc: 'Nền tảng nhà phát triển (hình ảnh)', + yunzhijiaModeHint: 'Hỗ trợ Webhook và WebSocket; chế độ WebSocket không yêu cầu URL callback công khai.', + yunzhijiaSendMsgUrl: 'URL gửi tin nhắn', + yunzhijiaSendMsgUrlHint: 'Dùng cho tin nhắn phản hồi của robot.', + yunzhijiaSecret: 'Khóa bí mật chữ ký (tùy chọn)', + yunzhijiaSecretPlaceholder: 'Khóa bí mật HmacSHA1 từ cài đặt robot Yunzhijia', + yunzhijiaSecretHint: 'Nếu cấu hình, các callback gửi đến sẽ được xác minh bằng chữ ký HmacSHA1', + yunzhijiaAppId: 'App ID (tải ảnh)', + yunzhijiaAppIdPlaceholder: 'App ID nền tảng mở Yunzhijia', + yunzhijiaAppSecret: 'App Secret (tải ảnh)', + yunzhijiaAppSecretPlaceholder: 'App Secret nền tảng mở Yunzhijia', + yunzhijiaAppCredentialHint: 'Dùng để lấy appAccessToken và tải ảnh do người dùng gửi.', + yunzhijiaTimeout: 'Thời gian chờ HTTP (giây)', + yunzhijiaTimeoutHint: 'Thời gian chờ gửi phản hồi qua URL gửi tin nhắn, mặc định 10 giây', + yunzhijiaAllowedHostSuffix: 'Hậu tố máy chủ được phép', + yunzhijiaAllowedHostSuffixHint: 'Giới hạn máy chủ URL gửi tin nhắn theo hậu tố này để đảm bảo an toàn (ví dụ: yunzhijia.com)', + yunzhijiaSendMsgUrlRequired: 'Nhập URL gửi tin nhắn từ cài đặt robot Yunzhijia', + mattermostModeHint: 'Mattermost chỉ hỗ trợ chế độ Webhook (outgoing webhook + bot token).', + mattermostPostToMain: 'Đăng phản hồi vào dòng thời gian kênh', + mattermostPostToMainHint: 'Khi bật, phản hồi của bot sẽ tạo bài đăng mới trong kênh. Khi tắt (mặc định), phản hồi sẽ nằm trong luồng thảo luận.', + modeHint: 'Khuyến nghị dùng WebSocket để thiết lập dễ dàng hơn', + consoleTip: 'để lấy thông tin xác thực', + wecomWSEndpointHint: 'Tùy chọn. Đối với bản WeCom nội bộ (on-premise), hãy nhập địa chỉ WebSocket tùy chỉnh. Để trống để dùng endpoint đám mây mặc định. Với địa chỉ mạng nội bộ, hãy thêm hostname vào biến môi trường SSRF_WHITELIST.', + wecomAPIBaseURLHint: 'Tùy chọn. Đối với bản WeCom nội bộ (on-premise), hãy nhập API base URL tùy chỉnh. Để trống để dùng endpoint đám mây mặc định. Với địa chỉ mạng nội bộ, hãy thêm hostname vào biến môi trường SSRF_WHITELIST.', + feishuAPIBaseURLHint: 'Tùy chọn. Để trống nếu máy chủ kết nối Internet trực tiếp; nếu cần proxy để truy cập Feishu, hãy nhập URL reverse proxy (ví dụ: nginx, http://host:port). Với địa chỉ mạng nội bộ, hãy thêm hostname vào biến môi trường SSRF_WHITELIST.', + fileKnowledgeBase: 'Kho tri thức lưu trữ tệp', + fileKnowledgeBasePlaceholder: 'Chọn kho tri thức (tùy chọn)', + fileKnowledgeBaseHint: 'Khi được cấu hình, tệp do người dùng gửi sẽ tự động lưu vào kho tri thức này', + sessionMode: 'Chế độ phiên', + sessionModeUser: 'Theo người dùng (mặc định)', + sessionModeThread: 'Theo luồng tin nhắn', + sessionModeHint: 'Chế độ người dùng: mỗi người có một cuộc hội thoại riêng (dùng /clear để đặt lại). Chế độ luồng: mỗi luồng tin nhắn là một phiên riêng biệt, hỗ trợ cộng tác nhóm.', + replyLanguage: 'Ngôn ngữ phản hồi', + replyLanguageDefault: 'Theo mặc định hệ thống', + replyLanguageHint: 'Cố định ngôn ngữ phản hồi của Agent cho kênh này. Để trống để dùng mặc định của hệ thống.', + wechatScanBind: 'Quét mã để liên kết WeChat', + wechatScanning: 'Quét mã QR bằng WeChat', + wechatBindSuccess: 'Liên kết WeChat thành công', + wechatRebind: 'Liên kết lại', + wechatHint: 'Yêu cầu WeChat iOS 8.0.70 trở lên, chỉ hỗ trợ tin nhắn trực tiếp', + wechatQRExpired: 'Mã QR đã hết hạn, vui lòng thử lại', + wechatBinding: 'Đang liên kết...', + sectionChannel: 'Thông tin kênh', + sectionConnection: 'Kết nối', + sectionCredentials: 'Thông tin xác thực nền tảng', + selectPlatform: 'Chọn nền tảng', + selectPlatformDesc: 'Chọn nền tảng nhắn tin cần kết nối', + enabled: 'Kích hoạt kênh', + stepBasic: 'Thông tin cơ bản', + stepConnection: 'Kết nối', + stepKnowledge: 'Lưu trữ tệp', + stepCredentials: 'Thông tin xác thực', + sectionAccess: 'Truy cập & phản hồi', + sectionSession: 'Phiên trò chuyện', + sectionCallback: 'URL Callback', + sectionKnowledge: 'Lưu trữ tệp', + sectionStatus: 'Trạng thái' + }, + agentType: { + label: 'Loại Agent', + desc: 'Chọn mẫu thiết lập sẵn để tự động điền câu lệnh hệ thống, danh sách công cụ và phạm vi kho tri thức đề xuất.', + defaultNamePattern: '{label} của tôi', + kbMismatch: { + ragQa: 'Chưa bật truy xuất RAG', + wikiQa: 'Chưa bật Wiki', + hybridRagWiki: 'Chưa bật phương thức truy xuất', + dataAnalysis: 'Yêu cầu RAG (không hỗ trợ FAQ)', + quickAnswer: 'Chế độ Trả lời nhanh yêu cầu truy xuất RAG', + generic: 'Không tương thích với loại hiện tại' + }, + kbIncompatibleWarn: '{count} kho tri thức đã chọn không tương thích với loại này, vui lòng tùy chỉnh lại.' + }, + mcp: { + label: 'Dịch vụ MCP', + desc: 'Chọn các dịch vụ MCP khả dụng cho Agent', + selectLabel: 'Chọn dịch vụ MCP', + selectDesc: 'Chọn các dịch vụ MCP cần kích hoạt', + selectPlaceholder: 'Chọn dịch vụ MCP', + authWaitTimeout: 'Thời gian chờ xác thực (giây)', + authWaitTimeoutDesc: 'Thời gian tối đa (giây) chờ hoàn tất xác thực OAuth trong hội thoại; sẽ bỏ qua yêu cầu nếu hết hạn (chỉ áp dụng cho dịch vụ MCP OAuth).', + authWaitTimeoutPlaceholder: 'Mặc định 600 giây', + unavailableService: 'Dịch vụ không khả dụng' + }, + llmCallTimeout: { + label: 'Thời gian chờ gọi LLM', + desc: 'Thời gian chờ tối đa cho một lệnh gọi LLM (giây). Sẽ hủy lệnh gọi nếu vượt quá giới hạn', + hint: 'Để trống hoặc nhập 0 để dùng mặc định (120 giây)', + placeholder: 'Nhập số giây, khuyến nghị từ 60-1800' + }, + imageUpload: { + navLabel: 'Tải lên tệp đính kèm', + sectionTitle: 'Tải lên tệp đính kèm', + sectionDesc: 'Cấu hình tệp đính kèm hình ảnh, tài liệu và âm thanh trong đoạn chat, cùng quy tắc phân tích và mô hình liên quan', + label: 'Tải lên hình ảnh', + desc: 'Cho phép tải hình ảnh trong đoạn chat để mô hình VLM đọc hiểu', + vlmModel: 'Mô hình VLM', + vlmModelDesc: 'Mô hình ngôn ngữ thị giác để phân tích hình ảnh', + vlmModelPlaceholder: 'Chọn mô hình VLM', + vlmModelRequired: 'Bắt buộc chọn mô hình VLM khi bật tải ảnh', + imageUnderstandingLabel: 'Đọc hiểu ảnh đính kèm / OCR bản quét', + imageUnderstandingDesc: 'Dành cho PDF/PPT dạng ảnh (tài liệu quét), chạy VLM OCR khi không trích xuất được văn bản. Làm tăng độ trễ phân tích; mặc định tắt.', + ocrMaxPagesLabel: 'Số trang OCR quét tối đa', + ocrMaxPagesDesc: 'Số trang quét tối đa gửi tới VLM để OCR. Càng nhiều trang độ bao phủ càng cao nhưng phân tích lâu và tốn chi phí hơn. 0 dùng mặc định hệ thống.', + useGlobalDefault: '0 = mặc định hệ thống', + storageProvider: 'Bộ lưu trữ hình ảnh', + storageProviderDesc: 'Bộ lưu trữ cho hình ảnh tải lên. Để trống để dùng mặc định hệ thống', + storageProviderPlaceholder: 'Chọn bộ lưu trữ', + storageDefault: 'Mặc định hệ thống', + notConfigured: 'Chưa cấu hình', + goStorageSettings: 'Đến Cài đặt lưu trữ' + }, + audioUpload: { + label: 'Tải lên âm thanh', + desc: 'Khi bật, người dùng có thể tải lên tệp âm thanh trong đoạn chat. Hệ thống sẽ tự động chuyển ngữ bằng mô hình ASR.', + asrModel: 'Mô hình ASR', + asrModelDesc: 'Mô hình nhận dạng giọng nói để chuyển ngữ. Nếu không cấu hình, tệp âm thanh sẽ được truyền dưới dạng giữ chỗ.', + asrModelPlaceholder: 'Chọn mô hình ASR' + }, + chatParser: { + label: 'Quy tắc phân tích tệp đính kèm chat', + desc: 'Chọn công cụ phân tích theo từng loại tệp cho tệp đính kèm của agent này.', + waitTimeoutLabel: 'Thời gian chờ phân tích tệp đính kèm (giây)', + waitTimeoutDesc: 'Thời gian lượt chat chờ các tệp đang phân tích trước khi tiếp tục với các tệp đã xong. Tăng lên đối với tệp lớn / tệp quét. 0 dùng mặc định hệ thống.' + }, + faq: { + title: 'Chiến lược ưu tiên FAQ', + enableLabel: 'Bật ưu tiên FAQ', + enableDesc: 'Câu trả lời từ FAQ sẽ được ưu tiên hơn tài liệu thông thường, giúp tăng độ chính xác phản hồi', + thresholdLabel: 'Ngưỡng trả lời trực tiếp', + thresholdDesc: 'Khi độ tương đồng giữa câu hỏi và FAQ vượt ngưỡng này, sẽ dùng trực tiếp câu trả lời của FAQ', + boostLabel: 'Hệ số tăng điểm FAQ', + boostDesc: 'Nhân điểm liên quan của FAQ với hệ số này để xếp hạng cao hơn' + }, + dataAnalysis: { + enableLabel: 'Bật phân tích dữ liệu bảng', + enableDesc: 'Khi các Chunk truy xuất từ tệp CSV/Excel, yêu cầu LLM tạo truy vấn DuckDB SQL trước khi trả lời. Việc này thêm 1 lượt gọi LLM và vài giây trễ, chỉ bật khi cần phân tích dạng SQL.' + }, + fallback: { + fixed: 'Phản hồi cố định', + model: 'Mô hình tự tạo' + }, + fileTypes: { + label: 'Định dạng tệp hỗ trợ', + desc: 'Giới hạn các loại tệp có thể chọn, để trống để hỗ trợ tất cả', + allTypes: 'Tất cả định dạng', + pdf: 'Tài liệu PDF', + word: 'Tài liệu Word (.docx/.doc)', + textLabel: 'Văn bản', + text: 'Tệp văn bản thuần (.txt)', + markdown: 'Tài liệu Markdown', + csv: 'Tệp giá trị phân cách bằng dấu phẩy (.csv)', + excel: 'Bảng tính Excel (.xlsx/.xls)', + imageLabel: 'Hình ảnh', + image: 'Tệp hình ảnh (.jpg/.jpeg/.png)' + } + }, + datasource: { + syncFailed: 'Không thể kích hoạt đồng bộ', + pause: 'Tạm dừng', + resume: 'Tiếp tục', + paused: 'Đã tạm dừng', + resumed: 'Đã tiếp tục', + pauseFailed: 'Tạm dừng thất bại', + logs: 'Nhật ký', + syncModeLabel: 'Chế độ đồng bộ', + syncMode: { + incremental: 'Gia tăng', + full: 'Toàn bộ' + }, + status: { + active: 'Đã kết nối', + paused: 'Đã tạm dừng', + error: 'Lỗi' + }, + createTitle: 'Thêm nguồn dữ liệu', + editTitle: 'Chỉnh sửa nguồn dữ liệu', + nameLabel: 'Tên', + namePlaceholder: 'Nhập tên nguồn dữ liệu', + sectionBasic: 'Thông tin cơ bản', + testConnection: 'Kiểm tra kết nối', + testSuccess: 'Kết nối thành công', + testFailed: 'Kết nối thất bại', + connected: 'Đã kết nối', + connectionFailed: 'Kết nối thất bại', + isRequired: 'là bắt buộc', + credentialsLabel: 'thông tin xác thực', + gitlab: { + baseUrl: 'GitLab URL', + accessToken: 'Personal access token', + projects: 'Dự án GitLab', + projectsHint: 'Nhập ID dự án hoặc đường dẫn namespace (ví dụ: group/project), có thể chỉ định nhánh và thư mục.', + project: 'Dự án', + projectId: 'ID dự án', + projectIdPlaceholder: 'Ví dụ: 12345 hoặc group/project', + ref: 'Nhánh', + refPlaceholder: 'Để trống để dùng nhánh mặc định', + paths: 'Thư mục', + pathsPlaceholder: 'Mỗi thư mục một dòng; để trống để đồng bộ toàn bộ dự án', + addProject: 'Thêm dự án', + projectRequired: 'Thêm ít nhất một dự án GitLab' + }, + resourceHint: 'Chọn không gian hoặc thư mục cần đồng bộ', + untitled: 'Không có tiêu đề', + resourceLoadFailed: 'Tải tài nguyên thất bại', + noResources: 'Không tìm thấy không gian wiki', + noResourcesDesc: 'Ứng dụng cần quyền truy cập wiki qua nhóm chat để lấy nội dung', + noResourcesDesc_notion: 'Ứng dụng cần quyền truy cập trang Notion để lấy nội dung', + retryLoadResources: 'Thử lại', + guideStep1: 'Tạo nhóm chat trong Feishu, sau đó thêm ứng dụng làm bot trong cài đặt nhóm', + guideStep2: 'Mở wiki > "Cài đặt" > "Cài đặt thành viên" > "Thêm thành viên", tìm nhóm chat và thêm vào', + guideStep3: 'Đảm bảo vai trò của nhóm chat tối thiểu là "Có thể đọc", sau đó quay lại và nhấn Thử lại', + guideStep1_notion: 'Mở trang hoặc cơ sở dữ liệu cần đồng bộ trong Notion', + guideStep2_notion: 'Nhấp vào biểu tượng "···" ở góc trên bên phải, chọn "Connect to" hoặc "Add connections"', + guideStep3_notion: 'Tìm và chọn ứng dụng tích hợp của bạn, sau đó quay lại và nhấn Thử lại', + permissionDocLink: 'Xem tài liệu cấp quyền Feishu wiki', + syncScheduleLabel: 'Lịch đồng bộ', + conflictLabel: 'Xử lý xung đột', + conflict: { + overwrite: 'Ghi đè', + skip: 'Bỏ qua nếu đã có' + }, + syncDeletions: 'Đồng bộ thao tác xóa (xóa tri thức khi nguồn bị xóa)', + createAndSync: 'Tạo & Đồng bộ ngay', + createAndSyncSuccess: 'Đã tạo nguồn dữ liệu và gửi tác vụ đồng bộ', + createButSyncFailed: 'Đã tạo nguồn dữ liệu nhưng không thể khởi chạy đồng bộ', + updateSuccessSyncHint: 'Đã cập nhật nguồn dữ liệu. Thay đổi sẽ không tự động đồng bộ; nhấp Đồng bộ để cập nhật.', + saveFailed: 'Lưu thất bại', + step: { + selectType: 'Chọn loại', + credentials: 'Xác thực', + resources: 'Tài nguyên', + strategy: 'Chiến lược' + }, + syncHistory: 'Lịch sử đồng bộ', + refreshLogs: 'Làm mới nhật ký', + noLogs: 'Chưa có bản ghi đồng bộ', + logStatus: { + running: 'Đang đồng bộ', + success: 'Thành công', + partial: 'Một phần', + failed: 'Thất bại', + canceled: 'Đã hủy' + }, + logMetric: { + total: 'Tổng', + skipped: 'đã bỏ qua', + failed: 'thất bại' + }, + logSummary: { + total: 'Lượt chạy', + success: 'Thành công', + failed: 'Thất bại', + items: 'Mục' + }, + logDetail: { + startTime: 'Bắt đầu', + endTime: 'Kết thúc', + failedItems: 'Tài liệu lỗi', + failedItemsMore: 'Còn {n} tài liệu lỗi khác chưa hiển thị', + docsFailedSummary: '{n} tài liệu đồng bộ thất bại' + }, + connector: { + feishu: 'Feishu', + lark: 'Lark', + feishu_drive: 'Feishu Drive', + lark_drive: 'Lark Drive', + notion: 'Notion', + confluence: 'Confluence', + yuque: 'Yuque', + dingtalk: 'DingTalk Docs', + rss: 'RSS / Atom Feed', + ima: 'Tencent IMA', + gitlab: 'GitLab' + }, + connectorDesc: { + feishu: 'Đồng bộ tài liệu, bảng tính và tệp từ Feishu Wiki', + lark: 'Đồng bộ tài liệu, bảng tính và tệp từ Lark Wiki (Feishu quốc tế)', + feishu_drive: 'Đồng bộ tài liệu, bảng tính và tệp từ thư mục Feishu Drive', + lark_drive: 'Đồng bộ tài liệu, bảng tính và tệp từ thư mục Lark Drive (Feishu quốc tế)', + notion: 'Đồng bộ trang và cơ sở dữ liệu từ Notion', + confluence: 'Đồng bộ không gian và trang từ Confluence dưới dạng Markdown', + yuque: 'Đồng bộ tài liệu từ các kho tri thức Yuque', + dingtalk: 'Đồng bộ tài liệu trực tuyến từ các kho tri thức DingTalk', + rss: 'Đồng bộ bài viết từ nguồn cấp RSS / Atom', + ima: 'Đồng bộ tài liệu, ghi chú và tệp từ kho tri thức Tencent IMA (không hỗ trợ phiên AI và phân tích video)', + gitlab: 'Đồng bộ tệp từ các dự án GitLab' + }, + title: 'Nguồn dữ liệu', + description: 'Cấu hình nguồn dữ liệu ngoài để đồng bộ nội dung vào kho tri thức này', + add: 'Thêm nguồn dữ liệu', + empty: 'Chưa cấu hình nguồn dữ liệu nào', + edit: 'Chỉnh sửa', + delete: 'Xóa', + deleteConfirm: 'Xóa nguồn dữ liệu này? Tri thức đã đồng bộ sẽ không bị xóa.', + deleteSuccess: 'Đã xóa nguồn dữ liệu', + deleteFailed: 'Xóa thất bại', + syncNow: 'Đồng bộ ngay', + syncTriggered: 'Đã gửi tác vụ đồng bộ', + back: 'Quay lại', + next: 'Tiếp tục', + save: 'Lưu', + schedule30min: 'Mỗi 30 phút', + schedule1h: 'Mỗi giờ', + schedule6h: 'Mỗi 6 giờ', + schedule12h: 'Mỗi 12 giờ', + schedule24h: 'Hàng ngày', + scheduleHuman: { + '30min': 'Mỗi 30 phút', + '1h': 'Hàng giờ', + '6h': 'Mỗi 6 giờ', + '12h': 'Mỗi 12 giờ', + '24h': 'Hàng ngày' + }, + resourceType: { + wikiSpace: 'Không gian Wiki', + docCategory: 'Thẻ tài liệu', + book: 'Sách Yuque' + }, + neverSynced: 'Chưa từng đồng bộ', + justNow: 'Vừa xong', + minutesAgo: '{n} phút trước', + hoursAgo: '{n} giờ trước', + daysAgo: '{n} ngày trước', + syncError: { + dingtalk_document_failed: 'Không thể đọc tài liệu DingTalk; vui lòng kiểm tra quyền truy cập và thử lại.', + dingtalk_resource_failed: 'Tài nguyên DingTalk không khả dụng; vui lòng kiểm tra quyền truy cập, tài nguyên đã chọn và thử lại.', + deletion_lookup_failed: 'Không tìm thấy mục cần xóa; xem nhật ký máy chủ', + deletion_failed: 'Xóa thất bại; xem nhật ký máy chủ', + ingest_failed: 'Nạp dữ liệu thất bại; xem nhật ký máy chủ' + }, + drive: { + folderTokenLabel: 'Folder token của Drive', + folderTokenPlaceholder: 'Nhập folder_token hoặc URL thư mục Feishu Drive', + folderTokenRequired: 'Vui lòng nhập folder_token cụ thể; không hỗ trợ thư mục gốc', + rootNotSupportedHint: 'Thư mục gốc không hỗ trợ phân trang và lối tắt; vui lòng chọn thư mục cụ thể', + load: 'Tải', + shareHint: 'Chia sẻ thư mục Drive với nhóm của ứng dụng trước để cấp quyền truy cập', + placeholderTitle: 'Tải thư mục Drive trước', + placeholderDesc: 'Nhập folder_token (hoặc dán URL thư mục Feishu Drive) ở trên rồi nhấn "Tải"', + loadForbiddenHint: 'Ứng dụng không có quyền truy cập thư mục này. Hãy chia sẻ thư mục với nhóm của ứng dụng trên Feishu Drive và thử lại.', + loadAuthHint: 'Thông tin xác thực không hợp lệ hoặc thiếu quyền Drive. Kiểm tra App ID / App Secret và quyền drive:drive:readonly.', + loadNotFoundHint: 'folder_token không tồn tại hoặc đã bị xóa. Vui lòng kiểm tra lại token từ URL thư mục Feishu Drive.' + }, + field: { + appId: 'App ID', + appSecret: 'App Secret', + clientId: 'Client ID', + clientSecret: 'Client Secret', + operatorId: 'Union ID người thao tác', + operatorIdHint: 'Đọc kho tri thức theo quyền của người dùng này. Lấy từ API chi tiết người dùng DingTalk.', + integrationToken: 'Integration Token', + apiToken: 'API Token', + confluenceEdition: 'Phiên bản', + confluenceEditionServer: 'Server / Data Center', + confluenceEditionCloud: 'Cloud', + confluenceBaseUrl: 'URL Confluence', + confluenceUsername: 'Tên đăng nhập hoặc email', + confluencePassword: 'Mật khẩu Server/DC', + confluenceApiToken: 'API token Cloud', + imaClientId: 'IMA ClientID', + imaApiKey: 'IMA APIKey', + baseUrl: 'Base URL (không bắt buộc)', + baseUrlHint: 'Để trống để dùng địa chỉ đám mây công cộng mặc định. Nhập địa chỉ tùy chỉnh nếu triển khai nội bộ/doanh nghiệp hoặc truy cập qua reverse proxy (vd: https://api-proxy.example.com).', + feedUrls: 'URL nguồn cấp', + feedUrlsHint: 'Mỗi dòng một URL nguồn cấp RSS / Atom; hỗ trợ nhiều nguồn.', + authHeaders: 'Header tùy chỉnh (không bắt buộc)', + authHeadersHint: 'Dành cho nguồn cấp riêng tư. Mỗi dòng một mục theo định dạng "Name: Value", vd: Authorization: Bearer xxxx' + }, + comingSoon: 'Sắp ra mắt', + docHint: 'Lấy thông tin xác thực tại:', + openDoc: 'Xem tài liệu', + prereqBarText: 'Lần đầu sử dụng? Bấm để xem hướng dẫn thiết lập ứng dụng Feishu', + prereqBarText_yuque: 'Lần đầu sử dụng? Bấm để xem hướng dẫn thiết lập Yuque token', + prereqStep1Brief_yuque: 'Tạo Yuque personal token', + prereqStep1Desc_yuque: 'Đăng nhập Yuque → Ảnh đại diện → Settings → Token → New Token', + prereqStep2Brief_yuque: 'Cấp quyền cho token', + prereqStep2Desc_yuque: 'Chọn tối thiểu repo:read và doc:read (đọc kho tri thức và nội dung tài liệu)', + prereqStep3Brief_yuque: '(Không bắt buộc) Nhập Base URL cho bản doanh nghiệp', + prereqStep3Desc_yuque: 'Để trống nếu dùng đám mây công cộng; nhập tên miền công ty nếu dùng Yuque Enterprise hoặc tự lưu trữ.', + prereqStep1Brief_feishu: 'Tạo ứng dụng tùy chỉnh Feishu', + prereqStep1Desc_feishu: 'Đăng nhập Nền tảng mở Feishu → Tạo ứng dụng doanh nghiệp tùy chỉnh', + prereqStep2Brief_feishu: 'Thêm tính năng Bot', + prereqStep2Desc_feishu: 'Nền tảng mở → Ứng dụng của bạn → Thêm tính năng ứng dụng → Bot', + prereqStep3Brief_feishu: 'Cấu hình quyền ứng dụng', + prereqStep3Desc_feishu: 'Bật các quyền: wiki:wiki:readonly, drive:drive:readonly, drive:export:readonly, docx:document:readonly', + prereqStep1Brief_lark: 'Tạo ứng dụng tùy chỉnh Lark', + prereqStep1Desc_lark: 'Đăng nhập Nền tảng mở Lark → Tạo ứng dụng doanh nghiệp tùy chỉnh', + prereqStep2Brief_lark: 'Thêm tính năng Bot', + prereqStep2Desc_lark: 'Nền tảng mở → Ứng dụng của bạn → Thêm tính năng ứng dụng → Bot', + prereqStep3Brief_lark: 'Cấu hình quyền ứng dụng', + prereqStep3Desc_lark: 'Bật các quyền: wiki:wiki:readonly, drive:drive:readonly, drive:export:readonly, docx:document:readonly', + prereqStep1Brief_feishu_drive: 'Tạo ứng dụng tùy chỉnh Feishu', + prereqStep1Desc_feishu_drive: 'Đăng nhập Nền tảng mở Feishu → Tạo ứng dụng doanh nghiệp tùy chỉnh', + prereqStep2Brief_feishu_drive: 'Thêm tính năng Bot', + prereqStep2Desc_feishu_drive: 'Nền tảng mở → Ứng dụng của bạn → Thêm tính năng ứng dụng → Bot', + prereqStep3Brief_feishu_drive: 'Cấu hình quyền ứng dụng', + prereqStep3Desc_feishu_drive: 'Bật các quyền: drive:drive:readonly, drive:export:readonly, docx:document:readonly', + prereqStep1Brief_lark_drive: 'Tạo ứng dụng tùy chỉnh Lark', + prereqStep1Desc_lark_drive: 'Đăng nhập Nền tảng mở Lark → Tạo ứng dụng doanh nghiệp tùy chỉnh', + prereqStep2Brief_lark_drive: 'Thêm tính năng Bot', + prereqStep2Desc_lark_drive: 'Nền tảng mở → Ứng dụng của bạn → Thêm tính năng ứng dụng → Bot', + prereqStep3Brief_lark_drive: 'Cấu hình quyền ứng dụng', + prereqStep3Desc_lark_drive: 'Bật các quyền: drive:drive:readonly, drive:export:readonly, docx:document:readonly', + prereqOpenConsole_yuque: 'Mở cài đặt Token Yuque', + prereqBarText_dingtalk: 'Lần đầu sử dụng? Bấm để xem hướng dẫn thiết lập ứng dụng DingTalk', + prereqStep1Brief_dingtalk: 'Tạo ứng dụng nội bộ doanh nghiệp', + prereqStep1Desc_dingtalk: 'Tạo ứng dụng nội bộ trên Nền tảng mở DingTalk và sao chép Client ID cùng Client Secret.', + prereqStep2Brief_dingtalk: 'Cấp quyền đọc kho tri thức', + prereqStep2Desc_dingtalk: 'Cấp các quyền: Wiki.Workspace.Read, Wiki.Node.Read và Storage.File.Read.', + prereqStep3Brief_dingtalk: 'Nhập Union ID người thao tác', + prereqStep3Desc_dingtalk: 'Nhập Union ID của người dùng DingTalk có quyền truy cập vào các kho tri thức đích.', + prereqOpenConsole_dingtalk: 'Mở Bảng điều khiển nhà phát triển DingTalk', + prereqBarText_ima: 'Lần đầu sử dụng? Bấm để xem hướng dẫn thiết lập Tencent IMA OpenAPI', + prereqStep1Brief_ima: 'Bật quyền truy cập IMA Agent OpenAPI', + prereqStep1Desc_ima: 'Đăng nhập https://ima.qq.com/agent-interface và đăng ký quyền truy cập OpenAPI', + prereqStep2Brief_ima: 'Lấy ClientID và APIKey', + prereqStep2Desc_ima: 'Sao chép thông tin xác thực ima-openapi-clientid và ima-openapi-apikey từ trang agent-interface', + prereqStep3Brief_ima: 'Ủy quyền truy cập kho tri thức đích', + prereqStep3Desc_ima: 'Trên ứng dụng IMA, cấp quyền cho thông tin xác thực đối với kho tri thức cần đồng bộ; kho chưa được cấp quyền sẽ không hiển thị trong danh sách', + prereqOpenConsole_ima: 'Mở bảng điều khiển Tencent IMA OpenAPI', + prereqBotBrief: 'Thêm tính năng "Bot" cho ứng dụng', + prereqBotDesc: 'Nền tảng mở > Thêm tính năng ứng dụng > Bot > tạo phiên bản và phát hành', + prereqPermBrief: 'Cấp quyền API', + prereqOpenConsole: 'Mở Bảng điều khiển nhà phát triển Feishu', + prereqMemberBrief: 'Thêm ứng dụng vào wiki qua nhóm chat', + prereqMemberDesc: 'Tạo nhóm chat > thêm ứng dụng dưới dạng bot > thêm nhóm chat vào thành viên wiki', + confluence: { + cloudFolderLimitation: 'Confluence Cloud không thể liệt kê các trang lưu trực tiếp dưới thư mục cấp cao nhất trong không gian này; chọn toàn bộ không gian vẫn sẽ đồng bộ được.' + }, + yuqueFolderModeLabel: 'Cấu trúc thư mục', + yuqueFolderModeToc: 'Phản chiếu mục lục Yuque (TOC)', + yuqueFolderModeNone: 'Giữ cấu trúc phẳng', + yuqueFolderModeHint: 'Lưu trữ tài liệu theo đường dẫn mục lục Yuque. Lưu ý: các thao tác di chuyển thư mục trong kho tri thức sau đó sẽ bị cấu trúc Yuque ghi đè ở lần đồng bộ tiếp theo.', + yuqueTOCOnly: 'Chỉ đồng bộ tài liệu hiển thị trong mục lục Yuque', + yuqueTOCOnlyHint: 'Yêu cầu bố cục "Phản chiếu mục lục Yuque (TOC)". Các tài liệu đã có trong kho tri thức được giữ nguyên — tài liệu không còn nằm trong mục lục Yuque sẽ không được thêm mới, không bao giờ bị xóa.' + }, + faqManager: { + import: { + recentResult: 'Kết quả nhập gần đây', + totalData: 'Tổng số dữ liệu', + success: 'Thành công', + added: 'Đã thêm', + merged: 'Đã hợp nhất', + partialFailed: 'Thất bại một phần', + failed: 'Thất bại', + skipped: 'Đã bỏ qua', + progressHint: 'Đang xác thực và nhập dữ liệu FAQ...', + downloadReasons: 'Tải xuống lý do lỗi', + appendMode: 'Chế độ ghi thêm', + replaceMode: 'Chế độ ghi đè', + importing: 'Đang nhập...', + importDone: 'Nhập hoàn tất', + importFailed: 'Nhập thất bại', + waiting: 'Đang chờ...', + importInProgress: 'Đang trong quá trình nhập, vui lòng đợi hoàn tất', + noFailedRecords: 'Không có bản ghi lỗi để tải xuống' + } + }, + mermaid: { + diagram: 'Sơ đồ', + expand: 'Mở rộng', + zoomIn: 'Phóng to', + zoomOut: 'Thu nhỏ', + reset: 'Đặt lại', + download: 'Tải ảnh xuống', + close: 'Đóng', + downloading: 'Đang tải xuống...' + }, + ollama: { + unknown: 'Không rõ', + today: 'Hôm nay', + yesterday: 'Hôm qua', + daysAgo: '{days} ngày trước' + }, + integrations: { + mcpserver: { + defaultAgentLabel: 'Agent mặc định', + defaultAgentPlaceholder: 'Mặc định trả lời nhanh khi để trống', + defaultAgentHint: 'Agent mà công cụ ask sẽ chạy. Client không thể tự chọn agent; để trống sẽ dùng tính năng trả lời nhanh tích hợp sẵn.', + sectionLimits: 'Giới hạn tốc độ', + rateLimitLabel: 'Số lượt gọi tối đa mỗi phút', + rateLimitHint: 'Áp dụng cho mọi lệnh gọi công cụ trên endpoint này; vượt quá sẽ trả về lỗi giới hạn tốc độ.', + sectionConnect: 'Kết nối', + stepConfig: 'Cấu hình', + stepConnect: 'Kết nối', + snippetsLabel: 'Cấu hình client', + connectHintExisting: 'Token chỉ hiển thị một lần khi tạo (token hiện tại bắt đầu bằng {hint}…). Tạo mới token để lấy mã khác.', + tokenDialogTitle: 'Endpoint đã sẵn sàng, hãy lưu token', + connectDialogTitle: 'Kết nối với endpoint này', + tokenOnce: 'Token này chỉ hiển thị một lần. Hãy sao chép và lưu trữ an toàn ngay bây giờ.', + connectPlaceholderHint: 'Vì lý do bảo mật, token sẽ không hiển thị lại; các ví dụ bên dưới sử dụng placeholder, hãy thay thế bằng token bạn đã lưu.', + tokenLabel: 'Token', + urlLabel: 'URL Endpoint', + snippet: { + httpTitle: 'Cursor / VS Code / Claude Desktop', + httpDesc: 'Dành cho các client hỗ trợ Streamable HTTP, dùng trực tiếp khối mcpServers này.', + claudeCodeTitle: 'Claude Code', + claudeCodeDesc: 'Chạy một lệnh duy nhất trong terminal.', + stdioTitle: 'Client chỉ hỗ trợ stdio', + stdioDesc: 'Cầu nối qua mcp-remote; yêu cầu cài đặt Node.js trên máy client.' + }, + loadFailed: 'Không thể tải danh sách endpoint MCP', + nameRequired: 'Vui lòng nhập tên', + updated: 'Đã cập nhật endpoint', + created: 'Đã tạo endpoint', + saveFailed: 'Lưu thất bại', + deleted: 'Đã xóa endpoint', + deleteFailed: 'Xóa thất bại', + rotated: 'Đã đổi token; token cũ đã vô hiệu', + rotateFailed: 'Đổi token thất bại', + disabledToast: 'Đã tắt endpoint', + enabledToast: 'Đã bật endpoint', + menuConnect: 'Thông tin kết nối', + menuDisable: 'Tắt', + menuEnable: 'Bật', + menuRotate: 'Đổi token', + copied: 'Đã sao chép', + deleteConfirm: 'Các client đang dùng endpoint này sẽ bị ngắt kết nối ngay lập tức. Bạn có chắc muốn xóa?', + title: 'MCP Server', + subtitle: 'Xuất bản không gian làm việc này thành MCP server để Claude Desktop, Cursor, Claude Code và các MCP client khác kết nối trực tiếp. Mỗi endpoint có token, phạm vi kho tri thức và danh sách công cụ riêng.', + listTitle: 'Endpoint đã xuất bản', + empty: 'Chưa có endpoint MCP nào', + disabled: 'Đã tắt', + cardSummary: '{tools} công cụ · {scope}', + scopeAll: 'Tất cả kho tri thức', + scopeCount: '{count} kho tri thức', + create: 'Tạo endpoint', + editTitle: 'Chỉnh sửa endpoint MCP', + createTitle: 'Tạo endpoint MCP', + drawerDesc: 'Endpoint quy định client có thể thấy những kho tri thức nào và gọi các công cụ nào. Token chỉ hiển thị một lần duy nhất khi tạo mới hoặc cấp lại.', + sectionBasic: 'Thông tin cơ bản', + nameLabel: 'Tên', + namePlaceholder: 'Ví dụ: Trợ lý tài liệu sản phẩm', + descriptionLabel: 'Mô tả', + descriptionPlaceholder: 'Tùy chọn: ai sử dụng endpoint này và mục đích là gì', + enabledLabel: 'Kích hoạt', + sectionScope: 'Phạm vi kho tri thức', + kbScopeLabel: 'Kho tri thức được phép truy cập', + kbScopePlaceholder: 'Để trống để áp dụng cho mọi kho tri thức trong không gian làm việc', + kbScopeHint: 'Mọi công cụ truy xuất, hỏi và ghi dữ liệu chỉ giới hạn trong các kho tri thức này. Để trống nghĩa là áp dụng cho toàn bộ không gian làm việc.', + sectionTools: 'Công cụ khả dụng', + toolsHint: 'Chỉ các công cụ được chọn mới xuất hiện trong danh sách của client; công cụ không chọn sẽ bị từ chối kể cả khi gọi đúng tên. Các công cụ ghi dữ liệu được tắt theo mặc định.', + clearGroup: 'Bỏ chọn tất cả', + selectGroup: 'Chọn tất cả', + toolsRequired: 'Chọn ít nhất một công cụ', + groups: { + retrieve: 'Truy xuất & Đọc dữ liệu', + chat: 'Hỏi đáp', + wiki: 'Wiki', + ingest: 'Ghi dữ liệu (cân nhắc cẩn thận)' + }, + tools: { + list_knowledge_bases: 'Liệt kê kho tri thức', + list_knowledge_basesDesc: 'Trả về danh sách kho tri thức trong phạm vi và các chế độ truy xuất hỗ trợ', + search_knowledge: 'Tìm kiếm ngữ nghĩa', + search_knowledgeDesc: 'Tìm các Chunk liên quan cho câu hỏi bằng ngôn ngữ tự nhiên, kèm nguồn trích dẫn', + grep_chunks: 'Tìm kiếm theo từ khóa / Regex', + grep_chunksDesc: 'Tìm regex không phân biệt chữ hoa/thường trên các đoạn thô; phù hợp cho thuật ngữ chính xác, mã số và tên riêng', + list_documents: 'Liệt kê tài liệu', + list_documentsDesc: 'Phân trang danh sách tài liệu trong một kho tri thức', + read_document: 'Đọc tài liệu', + read_documentDesc: 'Đọc metadata và các Chunk theo thứ tự của tài liệu', + ask: 'Hỏi đáp', + askDesc: 'Chạy agent được cấu hình trên endpoint này và trả về câu trả lời kèm trích dẫn; hỗ trợ hội thoại nhiều lượt', + wiki_search: 'Tìm kiếm wiki', + wiki_searchDesc: 'Tìm kiếm trong các trang wiki đã tạo', + wiki_read_page: 'Đọc trang wiki', + wiki_read_pageDesc: 'Đọc một trang wiki theo slug', + wiki_index: 'Xem mục lục wiki', + wiki_indexDesc: 'Hiển thị mục lục wiki của một kho tri thức', + add_document: 'Thêm tài liệu', + add_documentDesc: 'Thêm tài liệu từ văn bản Markdown hoặc URL', + update_document: 'Cập nhật tài liệu', + update_documentDesc: 'Thay thế nội dung hoặc tiêu đề của tài liệu Markdown', + delete_document: 'Xóa tài liệu', + delete_documentDesc: 'Xóa vĩnh viễn tài liệu và dữ liệu chỉ mục tương ứng' + }, + sectionAsk: 'Cài đặt hỏi đáp' + }, + tabs: { + im: 'Tích hợp IM', + embed: 'Nhúng Web', + api: 'Tích hợp API', + chrome: 'Tiện ích Chrome', + cli: 'CLI', + claw: 'Kỹ năng Claw', + mcpserver: 'MCP Server' + }, + api: { + title: 'Tích hợp API', + subtitle: 'Tích hợp qua REST API và cấu hình phương thức nhận diện người dùng cuối trong các yêu cầu.', + loading: 'Đang tải cài đặt tích hợp API...', + retry: 'Thử lại', + copy: 'Sao chép', + copySuccess: 'Đã sao chép', + baseUrl: 'URL cơ sở của API', + baseUrlDesc: 'Sử dụng URL cơ sở này cùng các đường dẫn REST API.', + apiKeys: 'API Key', + apiKeysDesc: 'Tạo các khóa riêng cho từng tích hợp, giới hạn quyền thao tác và phạm vi truy cập kho tri thức.', + createApiKey: 'Tạo API Key', + createApiKeyDialogDesc: 'Chọn quyền hạn và phạm vi kho tri thức mà khóa này được phép truy cập.', + noApiKeys: 'Chưa có API key nào', + apiKeyName: 'Tên', + apiKeyValue: 'API Key', + apiKeyNamePlaceholder: 'Ví dụ: Quyền chỉ đọc MCP', + apiKeyNameRequired: 'Vui lòng nhập tên API key', + apiKeyCapabilitiesRequired: 'Chọn ít nhất một quyền hạn cho API key theo phạm vi', + apiKeyAccessMode: 'Chế độ truy cập', + apiKeyScopedAccess: 'Truy cập theo phạm vi', + apiKeyAccessType: 'Loại truy cập', + apiKeyAccessTypeHint: '"Kho tri thức" hoạt động trong phạm vi kho tri thức theo phân quyền bên dưới; "Toàn quyền không gian làm việc" mở khóa thêm toàn bộ API cấp workspace như mô hình và nguồn dữ liệu.', + apiKeyCapabilities: 'Quyền hạn', + apiKeyCapabilityGroupKnowledge: 'Dữ liệu kho tri thức', + apiKeyCapabilityGroupAutomation: 'Agent và tích hợp', + apiKeyCapabilityGroupCollaboration: 'Thành viên và không gian', + apiKeyCapabilityGroupTenant: 'Cấu hình không gian làm việc', + apiKeyCapabilitySelectGroup: 'Chọn tất cả', + apiKeyCapabilityClearGroup: 'Bỏ chọn', + capabilityTenantFull: 'Toàn quyền không gian làm việc', + capabilityTenantFullHint: 'Cho phép truy cập mọi API cấp workspace, bao gồm mô hình, Vector Store, nguồn dữ liệu và kênh tích hợp. Không áp dụng giới hạn phạm vi kho tri thức.', + capabilityRetrieve: 'Truy xuất kho tri thức', + capabilityRetrieveHint: 'Đọc, truy vấn và tìm kiếm dữ liệu trong phạm vi kho tri thức đã chọn. Không tạo phiên làm việc hay chỉnh sửa nội dung.', + capabilityChat: 'Trò chuyện', + capabilityChatHint: 'Cho phép khóa này thực hiện hội thoại và quản lý phiên trò chuyện riêng. Không chỉnh sửa nội dung kho tri thức.', + capabilityReadAgents: 'Đọc thông tin agent', + capabilityReadAgentsHint: 'Xem danh sách agent, chi tiết agent, cấu hình sẵn và câu hỏi gợi ý. Không cho phép chat hoặc chỉnh sửa agent.', + capabilityIngest: 'Ghi nội dung kho tri thức', + capabilityIngestHint: 'Cho phép khóa này ghi nội dung vào các kho tri thức được chỉ định (tải lên tài liệu, chỉnh sửa Chunk/FAQ/thẻ/wiki). Không thể tạo hay xóa trắng kho tri thức, không tạo agent và chỉ giới hạn trong các kho tri thức đã chọn.', + capabilityManageKbs: 'Quản lý kho tri thức', + capabilityManageKbsHint: 'Cho phép khóa này quản lý toàn bộ vòng đời kho tri thức: tạo, sao chép, cập nhật, xóa kho tri thức và thay đổi khởi tạo/cấu hình. Thao tác trên kho tri thức sẵn có (sao chép/cập nhật/xóa) bị giới hạn trong phạm vi đã chọn; việc tạo kho tri thức mới không bị giới hạn (kho tri thức mới sẽ thuộc không gian làm việc này).', + capabilityManageAgents: 'Quản lý agent', + capabilityManageAgentsHint: 'Cho phép khóa này tạo, cập nhật, xóa và sao chép agent. Cấu hình agent có thể chứa liên kết mô hình/MCP nhạy cảm, nên mặc định tắt — chỉ bật khi cần thiết.', + capabilityMessageHistory: 'Lịch sử tin nhắn', + capabilityMessageHistoryHint: 'Cho phép khóa này tìm kiếm lịch sử chat và đọc số liệu thống kê lịch sử chat trong không gian làm việc. Không cấp quyền cấu hình không gian làm việc.', + capabilityManageModels: 'Quản lý mô hình', + capabilityManageModelsHint: 'Quản lý định nghĩa mô hình, thông tin xác thực, kiểm tra kết nối và thông tin xác thực WeKnoraCloud.', + capabilityManageMcpServices: 'Quản lý dịch vụ MCP', + capabilityManageMcpServicesHint: 'Quản lý dịch vụ MCP, thông tin xác thực, chính sách phê duyệt công cụ và trạng thái OAuth cho danh tính này.', + capabilityManageDatasources: 'Quản lý nguồn dữ liệu', + capabilityManageDatasourcesHint: 'Quản lý kết nối nguồn dữ liệu, thông tin xác thực, chọn tài nguyên và tác vụ đồng bộ. Phạm vi kho tri thức vẫn áp dụng khi nguồn dữ liệu được liên kết với một kho tri thức.', + capabilityManageChannels: 'Quản lý kênh', + capabilityManageChannelsHint: 'Quản lý kênh nhúng agent, kênh IM và quy trình liên kết mã QR WeChat.', + capabilityManageVectorStores: 'Quản lý hạ tầng truy xuất', + capabilityManageVectorStoresHint: 'Quản lý cấu hình Vector Store, trình phân tích, bộ đọc tài liệu và kiểm tra kết nối công cụ lưu trữ.', + capabilityManageStorageBackends: 'Quản lý bộ lưu trữ', + capabilityManageStorageBackendsHint: 'Quản lý các bộ lưu trữ tệp/đối tượng (như S3 hoặc bộ lưu trữ cục bộ): vòng đời CRUD, kiểm tra kết nối và lựa chọn mặc định của không gian làm việc.', + capabilityManageWebSearch: 'Quản lý tìm kiếm web', + capabilityManageWebSearchHint: 'Quản lý cấu hình nhà cung cấp tìm kiếm web, thông tin xác thực và kiểm tra kết nối.', + capabilityRunEvaluations: 'Chạy đánh giá', + capabilityRunEvaluationsHint: 'Chạy các tác vụ đánh giá và xem kết quả đánh giá.', + capabilityManageMembers: 'Quản lý thành viên', + capabilityManageMembersHint: 'Xem danh sách và quản lý thành viên, vai trò, lời mời và liên kết mời. Không bao gồm quản lý API key, xóa không gian làm việc hoặc chuyển quyền sở hữu.', + capabilityManageSpaces: 'Quản lý không gian', + capabilityManageSpacesHint: 'Quản lý không gian tổ chức, quy trình tham gia, tư cách thành viên, lời mời và chế độ hiển thị không gian chia sẻ. Không bao gồm chia sẻ kho tri thức hay agent.', + capabilityManageTenantSettings: 'Quản lý cài đặt không gian làm việc', + capabilityManageTenantSettingsHint: 'Xem và cập nhật cài đặt tích hợp cấp không gian làm việc như chế độ định danh người dùng cuối, cấu hình tiêu đề yêu cầu và cài đặt KV. Không bao gồm quản lý API key, thành viên, xóa không gian làm việc hoặc chuyển quyền sở hữu.', + apiKeyKnowledgeScope: 'Kho tri thức', + apiKeyKnowledgeScopePlaceholder: 'Để trống để áp dụng cho tất cả kho tri thức', + allKnowledgeBases: 'Tất cả kho tri thức', + editApiKeyScope: 'Chỉnh sửa API key', + editApiKeyScopeDesc: 'Đổi tên và phạm vi phân quyền cho API key "{name}".', + editApiKeyScopeHint: 'Để trống để áp dụng cho mọi kho tri thức trong không gian làm việc này. Thay đổi có hiệu lực ngay lập tức.', + updateApiKeyScopeSuccess: 'Đã cập nhật API key', + updateApiKeyScopeFailed: 'Cập nhật API key thất bại', + createdAt: 'Ngày tạo', + actions: 'Thao tác', + deleteApiKey: 'Xóa', + deleteApiKeyConfirm: 'Sau khi xóa, API key này sẽ bị thu hồi ngay lập tức và các tích hợp đang dùng khóa này sẽ ngừng hoạt động.', + deleteApiKeySuccess: 'Đã xóa API key', + deleteApiKeyFailed: 'Xóa API key thất bại', + createApiKeyFailed: 'Tạo API key thất bại', + loadApiKeysFailed: 'Tải API key thất bại', + apiKeyCreated: 'Đã tạo API key', + principalMode: 'Chế độ định danh người dùng', + principalModeDesc: 'Chọn cách yêu cầu API xác định người dùng cuối. Định danh này phân tách phiên hội thoại và phân quyền công cụ MCP theo từng người dùng.', + principalScope: 'Định danh người dùng cuối giúp cô lập phiên và MCP OAuth. Quyền thao tác và phạm vi kho tri thức do API Key ở trên kiểm soát.', + modeTenant: 'Chỉ không gian làm việc', + modeDirect: 'ID người dùng trực tiếp', + modeSigned: 'Token có chữ ký', + directWarning: 'Chế độ này tin cậy tiêu đề do bên gọi gửi lên. Chỉ dùng cho các lệnh gọi máy chủ nội bộ tin cậy (server-to-server).', + directWarningDetail: 'Bất kỳ ai có API key đều có thể đổi tiêu đề ID người dùng để mạo danh người dùng khác và chiếm quyền sử dụng MCP OAuth của họ. Không dùng từ trình duyệt hoặc ứng dụng không tin cậy; hãy dùng Token có chữ ký cho ứng dụng người dùng cuối.', + signedRecommended: 'Khuyên dùng cho ứng dụng phía người dùng: backend của bạn tự ký một mã JWT HS256 ngắn hạn cho người dùng ngoài.', + signedFlowDetail: 'Chỉ lưu HMAC secret trên WeKnora và backend tin cậy—không đưa vào yêu cầu hay gửi về trình duyệt. Tiêu đề yêu cầu mang chuỗi JWT đã ký bằng secret đó (thay đổi theo mỗi lần cấp hoặc hết hạn), không phải secret gốc. JWT phải có sub (ID người dùng ngoài), tenant_id, aud=weknora và exp (tối đa 24 giờ).', + directHeader: 'Tiêu đề User ID', + requireDirectHeader: 'Bắt buộc có tiêu đề User ID', + requireDirectHeaderDesc: 'Khi bật, các yêu cầu API Key thiếu tiêu đề User ID sẽ bị từ chối; khi tắt, toàn bộ yêu cầu được coi là của chung không gian làm việc, không phân biệt người dùng.', + tokenHeader: 'Tiêu đề Token', + tokenHeaderDesc: 'Client gửi JWT do backend ký thông qua tiêu đề cố định này.', + hmacSecret: 'HMAC secret', + hmacSecretDesc: 'Khóa bí mật trùng với WeKnora; chỉ dùng ở backend để ký JWT—tuyệt đối không gửi trực tiếp trong tiêu đề yêu cầu.', + secretConfigured: 'Secret đã cấu hình (sẽ không hiển thị lại); nhập giá trị mới để xoay vòng', + secretSavedCopyHint: 'Đã lưu secret. Hãy sao chép vào backend ngay — bạn sẽ không thể xem lại sau khi rời trang này.', + generateSecret: 'Tạo secret', + hmacSecretResetConfirmTitle: 'Đặt lại HMAC secret?', + hmacSecretResetConfirmBody: 'Sau khi đặt lại, HMAC secret cũ sẽ bị thu hồi ngay lập tức. Mọi dịch vụ backend đang ký JWT bằng secret cũ phải chuyển sang secret mới để tiếp tục gọi API. Thao tác này không thể hoàn tác.', + hmacSecretResetConfirmOk: 'Đặt lại', + hmacSecretResetConfirmCancel: 'Hủy', + tokenSignExample: 'Ví dụ ký JWT ở backend (Go)', + signedRequestStep0: '# 0. Ký JWT ở backend (HS256, aud=weknora, sub=user id, tenant_id={tenantId}, exp<=24h)', + signedRequestStep0Hint: '# Đặt JWT vào {headerName} — không phải HMAC secret', + requestExampleCreateSession: '# 1. Tạo phiên làm việc', + requestExampleAgentChat: '# 2. Chat với Agent (SSE; thay bằng id từ bước 1)', + requestExampleJwtPlaceholder: '', + requestExample: 'Ví dụ yêu cầu', + playgroundTitle: 'API Playground', + playgroundDesc: 'Gửi yêu cầu thực tế với API key và chế độ định danh hiện tại để kiểm tra việc tạo phiên, chat agent và đầu ra SSE.', + playgroundOpen: 'Mở Playground', + playgroundDrawerDesc: 'Gỡ lỗi phiên, Chat với Agent và đầu ra SSE bằng quy trình tích hợp API thực tế', + playgroundSectionRequest: 'Thiết lập yêu cầu', + playgroundSectionPreview: 'Xem trước yêu cầu', + playgroundSectionResult: 'Kết quả chạy', + playgroundAgent: 'Agent kiểm thử', + playgroundAgentPlaceholder: 'Chọn một agent để kiểm thử', + playgroundBuiltin: 'Tích hợp sẵn', + playgroundAgentsLoadFailed: 'Tải danh sách agent thất bại', + playgroundExternalUser: 'ID người dùng ngoài', + playgroundExternalUserPlaceholder: 'user_123', + playgroundTenantModeHint: 'Chế độ chỉ không gian làm việc không gửi định danh người dùng ngoài; mọi phiên API đều dùng chung định danh cấp không gian làm việc.', + playgroundDirectModeHint: 'ID người dùng này được gửi kèm trong tiêu đề {headerName}.', + playgroundSignedModeHint: 'Chế độ token có chữ ký dùng trường sub của JWT làm người dùng ngoài. Playground sẽ tự ký một JWT thử nghiệm ngắn hạn cho ID người dùng này.', + playgroundQuestion: 'Câu hỏi kiểm thử', + playgroundQuestionPlaceholder: 'Nhập câu hỏi để gửi tới agent', + playgroundRequestPreview: 'Xem trước yêu cầu (đã ẩn secret)', + playgroundRun: 'Chạy thử', + playgroundStop: 'Dừng', + playgroundNeedApiKey: 'Không gian làm việc này chưa có API key.', + playgroundNeedAgent: 'Vui lòng chọn một agent để kiểm thử.', + playgroundNeedQuestion: 'Vui lòng nhập câu hỏi kiểm thử.', + playgroundNeedExternalUser: 'Vui lòng nhập ID người dùng ngoài.', + playgroundMintTokenFailed: 'Tạo JWT thử nghiệm ngắn hạn thất bại.', + playgroundMissingSessionId: 'Tạo phiên thành công nhưng phản hồi không chứa session id.', + playgroundNoStream: 'API chat không trả về luồng SSE đọc được.', + playgroundGeneratedToken: 'Token thử nghiệm đã tạo', + playgroundStepSession: 'Bước 1: Tạo phiên', + playgroundStepChat: 'Bước 2: Chat với Agent qua SSE', + playgroundFinalAnswer: 'Câu trả lời trích xuất', + playgroundEmptyResult: 'Chạy thử để hiển thị phản hồi phiên, dữ liệu SSE thô và câu trả lời trích xuất tại đây.', + playgroundSuccess: 'Kiểm thử hoàn tất ({ms}ms)', + playgroundStopped: 'Đã dừng kiểm thử', + playgroundFailed: 'Kiểm thử API Playground thất bại', + loadFailed: 'Tải cài đặt tích hợp API thất bại', + saveFailed: 'Lưu cài đặt tích hợp API thất bại', + saveSuccess: 'Đã lưu cài đặt tích hợp API', + autoSaveNeedSecret: 'Chế độ Signed-token cần khoá bí mật HMAC trước khi tự động lưu.' + }, + cli: { + title: 'WeKnora CLI', + subtitle: 'Quản trị kho tri thức, tài liệu, tìm kiếm nội dung và đặt câu hỏi ngay từ terminal. Kết nối tập lệnh và công cụ AI qua CLI hoặc MCP.', + docs: 'Tài liệu CLI', + docsHint: 'Hướng dẫn cài đặt và danh mục lệnh đầy đủ', + quickstart: 'Bắt đầu nhanh', + installTitle: 'Cài đặt CLI', + installDesc: 'Build từ mã nguồn bằng Git và Go 1.26+. Lệnh mẫu macOS / Linux này chỉ cập nhật PATH cho phiên terminal hiện tại. Để dùng lâu dài, hãy chuyển tệp thực thi vào thư mục nằm trong PATH.', + connectTitle: 'Kết nối tới máy chủ này', + connectDesc: 'Tạo và kích hoạt hồ sơ tên weknora, sau đó đăng nhập bằng email và mật khẩu. Nếu hồ sơ đã tồn tại, hãy chọn tên khác và cập nhật tương ứng trong cấu hình MCP mẫu.', + verifyTitle: 'Xác minh kết nối', + verifyDesc: 'Kiểm tra trạng thái máy chủ và xác thực, sau đó liệt kê các kho tri thức mà tài khoản có quyền truy cập.', + commandsTitle: 'Lệnh phổ biến', + commandsDesc: 'Thay KB_ID bằng ID kho tri thức thực tế và điều chỉnh đường dẫn tệp, truy vấn và câu hỏi. Tài liệu tải lên cần xử lý xong trước khi có thể tìm kiếm.', + mcpTitle: 'Kết nối MCP client', + mcpDesc: 'Sau khi đăng nhập, thêm cấu hình này vào MCP client hỗ trợ stdio. Nếu client không tìm thấy weknora, hãy đặt command thành đường dẫn tuyệt đối của tệp thực thi.', + copy: 'Sao chép', + copied: 'Đã sao chép' + }, + title: 'Xuất bản & Tích hợp', + selectAgentPlaceholder: 'Chọn một agent', + selectAgentHint: 'Vui lòng chọn agent trước', + boundAgent: 'Agent liên kết', + filterByAgent: 'Lọc theo agent', + filterByAgentWithName: 'Lọc theo agent: {name}', + filterAllAgents: 'Tất cả agent', + imOverview: { + title: 'Kênh IM đã kết nối' + }, + embedOverview: { + title: 'Kênh nhúng web' + }, + agentEditor: { + label: 'Kênh phát hành', + desc: 'Phát hành agent này lên các nền tảng IM hoặc website. Quản lý trong mục Tích hợp.' + }, + chrome: { + title: 'Trợ lý tri thức', + subtitle: 'Dành cho WeKnora tự lưu trữ: hỏi đáp qua thanh bên, thu thập trang web và lưu ghi chú Markdown vào kho tri thức ngay khi duyệt web.', + capabilitiesTitle: 'Tính năng cốt lõi', + capabilities: { + qa: { + title: 'Hỏi đáp kho tri thức', + desc: 'Trò chuyện thanh bên, chuyển đổi nhiều kho tri thức và chọn chế độ nhanh/sâu/chính xác—hỏi đáp không cần rời trang.' + }, + clip: { + title: 'Lưu trang web một chạm', + desc: 'Lưu URL, trích xuất nội dung chính bằng AI hoặc tự chọn vùng nội dung vào kho tri thức chỉ định.' + }, + notes: { + title: 'Ghi chú nhanh Markdown', + desc: 'Trình soạn thảo Markdown tích hợp sẵn cho ý tưởng và ghi chú, lưu vào kho tri thức với một cú nhấp.' + }, + shortcuts: { + title: 'Phím tắt', + desc: 'Tuỳ chỉnh phím tắt để đặt câu hỏi, mở thanh bên và tăng tốc quy trình làm việc hàng ngày.' + } + }, + scenarios: { + research: 'Nghiên cứu hàng ngày', + learning: 'Ghi chép học tập', + tech: 'Tài liệu kỹ thuật', + work: 'Tri thức công việc' + }, + stepsTitle: 'Các bước thiết lập', + steps: { + api: { + title: 'Lấy thông tin xác thực API', + desc: 'Sao chép API Key và Base URL từ Cài đặt → Thông tin API.' + }, + port: { + title: 'Desktop: cổng cố định (khuyên dùng)', + desc: 'Trên WeKnora Desktop, thiết lập cổng API cố định (ví dụ: 37841) trong Thông tin API để URL không đổi sau mỗi lần khởi động lại.' + }, + install: { + title: 'Cài đặt tiện ích mở rộng', + desc: 'Cài đặt “Knowledge Assistant” từ Chrome Web Store.' + }, + connect: { + title: 'Kết nối trong tiện ích', + desc: 'Mở cài đặt tiện ích, chọn chế độ doanh nghiệp/nhà phát triển và nhập URL API dịch vụ cùng API Key. URL API hiện tại được hiển thị bên dưới.' + } + }, + openApiSettings: 'Mở Thông tin API', + copy: 'Sao chép', + copySuccess: 'Đã sao chép URL API', + installCta: 'Chrome Web Store', + installCtaHint: 'Tiện ích chính thức · mở trong tab mới', + storeMeta: 'Chrome Web Store · v1.0.0' + }, + claw: { + title: 'WeKnora Skill', + subtitle: 'Nhập tài liệu và truy xuất kết hợp (vector + từ khóa) qua WeKnora REST API—hỗ trợ tải lên, nhập qua URL, ghi chú Markdown và tìm kiếm liên kho tri thức.', + capabilitiesTitle: 'Tính năng kỹ năng', + capabilities: { + upload: { + title: 'Tải tệp lên', + desc: 'Tải lên PDF, Word, Excel và nhiều định dạng khác; tự động phân tích cú pháp và Embedding.' + }, + url: { + title: 'Nhập URL', + desc: 'Thu thập trang web theo URL vào kho tri thức kèm theo dõi trạng thái xử lý.' + }, + manual: { + title: 'Soạn Markdown', + desc: 'Tạo hoặc chỉnh sửa nội dung tri thức dưới dạng Markdown—lý tưởng cho biên bản cuộc họp.' + }, + search: { + title: 'Tìm kiếm kết hợp', + desc: 'Tìm kiếm kết hợp theo từng kho và tìm kiếm liên kho tri thức, kết hợp giữa vector và từ khoá.' + }, + browse: { + title: 'Duyệt tri thức', + desc: 'Xem danh sách kho tri thức và mục nội dung, xem chi tiết và quản lý nội dung đã nhập.' + } + }, + stepsTitle: 'Các bước thiết lập', + steps: { + api: { + title: 'Lấy thông tin xác thực API', + desc: 'Sao chép API Key và Base URL từ Cài đặt → Thông tin API.' + }, + env: { + title: 'Cấu hình môi trường', + desc: 'Đặt WEKNORA_BASE_URL và WEKNORA_API_KEY trong shell hoặc tệp ~/.zshrc / ~/.bashrc. Ví dụ bên dưới dùng Base URL hiện tại của bạn—vui lòng thay API Key bằng giá trị thực tế.' + }, + install: { + title: 'Cài đặt kỹ năng', + desc: 'Chạy lệnh bên dưới trong môi trường đã cài OpenClaw CLI, hoặc làm theo hướng dẫn trên trang ClawHub.' + }, + verify: { + title: 'Kiểm tra kết nối', + desc: 'Yêu cầu agent liệt kê kho tri thức hoặc thử tìm kiếm để xác nhận thông tin xác thực và kết nối.' + } + }, + openApiSettings: 'Mở Thông tin API', + copy: 'Sao chép', + copyEnvSuccess: 'Đã sao chép ví dụ biến môi trường', + copyCmdSuccess: 'Đã sao chép lệnh cài đặt', + ecosystemNote: 'Kỹ năng được lưu trữ trên ClawHub ({\'@\'}lyingbug/weknora). Xem trang ClawHub để biết đầy đủ tài liệu API và lịch sử phiên bản.', + installCta: 'Mở ClawHub', + installCtaHint: 'Cài đặt WeKnora Skill · mở trong tab mới', + hubMeta: 'ClawHub · {\'@\'}lyingbug/weknora · MIT-0' + } + }, + credential: { + configured: 'Đã cấu hình', + unconfigured: 'Chưa cấu hình', + configure: 'Cấu hình', + update: 'Thay đổi', + remove: 'Xoá', + inputPlaceholder: 'Nhập giá trị', + savedToast: 'Đã lưu thông tin xác thực', + saveFailed: 'Không thể lưu thông tin xác thực', + removedToast: 'Đã xoá thông tin xác thực', + removeFailed: 'Không thể xoá thông tin xác thực', + confirmRemovePrompt: 'Xoá thông tin xác thực này? Thao tác này không thể hoàn tác.', + confirmRemove: 'Xác nhận xoá' + }, + userProfile: { + title: 'Hồ sơ người dùng', + description: 'Xem thông tin tài khoản (ID người dùng, tên đăng nhập, email, thời gian đăng ký) và đổi mật khẩu.', + changePassword: { + label: 'Đổi mật khẩu', + description: 'Xác thực mật khẩu hiện tại, sau đó thiết lập mật khẩu mới. Tất cả phiên đăng nhập sẽ bị thu hồi và bạn sẽ cần đăng nhập lại.', + currentLabel: 'Mật khẩu hiện tại', + currentPlaceholder: 'Nhập mật khẩu hiện tại', + currentRequired: 'Vui lòng nhập mật khẩu hiện tại', + newLabel: 'Mật khẩu mới', + newPlaceholder: 'Nhập mật khẩu mới', + confirmLabel: 'Xác nhận mật khẩu mới', + confirmPlaceholder: 'Nhập lại mật khẩu mới', + submit: 'Cập nhật mật khẩu', + success: 'Đã cập nhật mật khẩu. Vui lòng đăng nhập lại bằng mật khẩu mới.', + failed: 'Đổi mật khẩu thất bại. Vui lòng kiểm tra lại mật khẩu hiện tại.', + policyFailed: 'Mật khẩu mới phải từ 8-32 ký tự, bao gồm cả chữ và số', + sameAsCurrent: 'Mật khẩu mới không được trùng với mật khẩu hiện tại', + oidcOnlyDescription: 'Tài khoản của bạn được tạo qua OIDC và chưa thiết lập mật khẩu cục bộ.', + oidcOnlyNotice: 'Vui lòng liên hệ quản trị viên để đặt lại mật khẩu hoặc tiếp tục đăng nhập bằng OIDC. Tính năng tự đổi mật khẩu yêu cầu mật khẩu hiện tại.' + } + }, + tenantMember: { + title: 'Thành viên', + sectionDescription: 'Mời đồng nghiệp vào không gian làm việc và phân quyền. Chỉ Chủ sở hữu mới có quyền thêm hoặc xóa thành viên.', + learnRbacGuide: 'Tìm hiểu về RBAC', + listTitle: 'Thành viên không gian làm việc', + loading: 'Đang tải danh sách thành viên…', + retry: 'Thử lại', + empty: 'Chưa có thành viên nào. Hãy mời đồng nghiệp để bắt đầu.', + emptySearch: 'Không tìm thấy thành viên nào khớp với "{q}".', + searchPlaceholder: 'Tìm theo tên hoặc email', + permissions: { + title: 'Quyền của vai trò', + desc: 'Quyền hạn của từng vai trò trong không gian làm việc này. Được kiểm soát từ phía máy chủ; giao diện chỉ phản ánh các quy tắc này.', + iconHint: 'Di chuột để xem chi tiết quyền của vai trò', + manageMembers: 'Quản lý thành viên', + manageTenantConfig: 'Chỉnh sửa cài đặt không gian làm việc', + manageInfra: 'Cấu hình mô hình / Vector Store / kênh IM', + createOwnKB: 'Tạo và chỉnh sửa kho tri thức & agent của riêng mình', + readAll: 'Xem nội dung không gian làm việc' + }, + columns: { + member: 'Tên & email', + role: 'Vai trò', + joinedAt: 'Ngày tham gia', + operations: 'Thao tác' + }, + role: { + owner: 'Chủ sở hữu', + admin: 'Quản trị viên', + contributor: 'Cộng tác viên', + viewer: 'Người xem' + }, + add: { + button: 'Thêm thành viên', + dialogTitle: 'Mời thành viên', + emailLabel: 'Email', + emailPlaceholder: 'nguoiduocmoi{\'@\'}example.com', + roleLabel: 'Vai trò' + }, + remove: { + button: 'Xóa', + confirmBody: 'Bạn có chắc muốn xóa {name} khỏi không gian làm việc này? Quyền truy cập của họ sẽ bị thu hồi ngay lập tức.', + confirm: 'Xóa', + success: 'Đã xóa thành viên' + }, + leave: { + confirmTitle: 'Rời khỏi không gian làm việc này?', + confirmBody: 'Bạn sẽ mất quyền truy cập vào tất cả kho tri thức và agent trong không gian làm việc này. Bạn có thể được mời lại sau.', + confirm: 'Rời khỏi', + success: 'Bạn đã rời khỏi không gian làm việc' + }, + roleChange: { + success: 'Đã cập nhật vai trò' + }, + errors: { + emailRequired: 'Vui lòng nhập email', + emailFormat: 'Email không hợp lệ', + roleRequired: 'Vui lòng chọn vai trò', + userNotFound: 'Không tìm thấy người dùng với email này. Vui lòng yêu cầu họ đăng ký trước.', + lastOwner: 'Không thể giáng cấp, xóa hoặc rời đi khi bạn là Chủ sở hữu duy nhất. Hãy chỉ định một Chủ sở hữu khác trước.', + notFound: 'Không tìm thấy tư cách thành viên.', + invalidRole: 'Vai trò phải là chủ sở hữu / quản trị viên / cộng tác viên / người xem.', + generic: 'Đã xảy ra lỗi. Vui lòng thử lại.' + }, + audit: { + tabLabel: 'Audit Log', + description: 'Ghi lại mọi thay đổi thành viên và từ chối truy cập trong không gian làm việc này. Mới nhất xếp trước. Các lượt từ chối lặp lại trong vòng một phút sẽ được gộp.', + refresh: 'Làm mới', + end: 'Hết nhật ký.', + empty: 'Chưa có sự kiện nhật ký nào.', + forbidden: 'Bạn không có quyền xem Audit Log.', + systemActor: 'Hệ thống', + requiredRole: 'Yêu cầu vai trò: {role}', + columns: { + time: 'Thời gian', + actor: 'Người thực hiện', + action: 'Hành động', + target: 'Đối tượng', + path: 'Yêu cầu', + outcome: 'Kết quả' + }, + action: { + rbac: { + member_added: 'Đã thêm thành viên', + member_removed: 'Đã xóa thành viên', + member_role_changed: 'Đã đổi vai trò', + member_left: 'Đã rời khỏi', + access_denied: 'Từ chối truy cập', + invitation_sent: 'Đã gửi lời mời', + invitation_accepted: 'Đã chấp nhận lời mời', + invitation_declined: 'Đã từ chối lời mời', + invitation_revoked: 'Đã thu hồi lời mời', + invitation_expired: 'Lời mời đã hết hạn' + } + }, + outcome: { + success: 'Thành công', + denied: 'Bị từ chối' + }, + expanded: { + actorId: 'ID người thực hiện', + targetUserId: 'ID người dùng đích', + targetType: 'Loại đối tượng', + targetId: 'ID đối tượng', + details: 'Chi tiết thô' + } + } + }, + tenantInvitation: { + inboxTooltip: 'Xem lời mời đang chờ', + pendingSectionTitle: 'Lời mời đang chờ', + pendingSectionDesc: 'Đang chờ người được mời chấp nhận trong hộp thư của họ. Tự động hết hạn sau {days} ngày.', + pendingEmpty: 'Không có lời mời nào đang chờ.', + inviteSubmit: 'Gửi lời mời', + inviteSuccess: 'Đã gửi lời mời. Đang chờ người nhận chấp nhận.', + confirmInviteTitle: 'Gửi lời mời?', + confirmInviteBody: 'Gửi lời mời tới {email} (vai trò: {role}). Họ sẽ chỉ tham gia không gian làm việc sau khi chấp nhận.', + confirmSend: 'Gửi', + copyLink: 'Sao chép liên kết mời', + copied: 'Đã sao chép vào khay nhớ tạm', + copyFailed: 'Sao chép thất bại; vui lòng chọn văn bản thủ công', + shareLink: { + button: 'Tạo liên kết chia sẻ', + cellTitle: 'Mời qua liên kết', + cellAccepted: '{count} đã tham gia', + cellEmpty: 'Chưa có ai tham gia', + dialogTitle: 'Tạo liên kết mời chia sẻ', + description: 'Tạo liên kết đăng ký dùng chung để chia sẻ trong nhóm trò chuyện. Bất kỳ ai mở liên kết sẽ đăng ký bằng email của họ và tham gia không gian làm việc này. Hết hạn sau {days} ngày, hoặc bạn có thể thu hồi bất cứ lúc nào từ danh sách.', + generate: 'Tạo liên kết', + resultTitle: 'Liên kết mời đã sẵn sàng', + resultBody: 'Sao chép liên kết dưới đây và chia sẻ qua kênh riêng tư. Liên kết cũng được lưu trong danh sách — bạn có thể sao chép lại hoặc thu hồi sau.', + revokeConfirm: 'Thu hồi sẽ chặn bất kỳ ai chưa đăng ký sử dụng liên kết này. Hãy tạo liên kết mới để chia sẻ lại.' + }, + revoke: { + button: 'Thu hồi', + confirmBody: 'Sau khi thu hồi, {email} sẽ không thể chấp nhận lời mời này. Bạn có thể gửi lời mời mới nếu cần.', + confirm: 'Thu hồi', + success: 'Đã thu hồi lời mời.' + }, + columns: { + invitee: 'Người được mời', + role: 'Vai trò', + inviter: 'Người mời', + expiresAt: 'Hết hạn', + status: 'Trạng thái', + operations: 'Thao tác' + }, + status: { + pending: 'Đang chờ', + shareLinkActive: 'Đang hoạt động', + accepted: 'Đã chấp nhận', + declined: 'Đã từ chối', + revoked: 'Đã thu hồi', + expired: 'Đã hết hạn' + }, + myInbox: { + title: 'Lời mời của tôi', + description: 'Lời mời từ các không gian làm việc khác. Chấp nhận để tham gia với vai trò được chỉ định.', + empty: 'Không có lời mời nào đang chờ.', + acceptButton: 'Chấp nhận', + declineButton: 'Từ chối', + acceptSuccess: 'Đã tham gia "{tenant}".', + declineSuccess: 'Đã từ chối lời mời.', + from: 'Người gửi', + tenantLabel: 'Không gian làm việc', + expiresIn: 'Hết hạn: {date}', + messageLabel: 'Lời nhắn' + }, + errors: { + pendingExists: 'Đã có lời mời đang chờ cho người dùng này.', + alreadyMember: 'Người dùng này đã là thành viên của không gian làm việc.', + notPending: 'Lời mời không còn ở trạng thái chờ.', + forbidden: 'Chỉ người được mời mới có thể chấp nhận hoặc từ chối lời mời này.', + notFound: 'Không tìm thấy lời mời hoặc đã bị thu hồi.', + generic: 'Đã xảy ra lỗi. Vui lòng thử lại.' + } + }, + platformApiKeys: { + title: 'API Key nền tảng', + description: 'Tạo khoá xác thực nền tảng cho tự động hoá liên không gian làm việc. Sử dụng X-Tenant-ID cho các API không gian làm việc.', + securityNotice: 'API key nền tảng có thể truy cập mọi không gian làm việc. Chỉ cấp quyền cần thiết; khoá chỉ hiển thị một lần duy nhất.', + create: 'Tạo API key nền tảng', + createDescription: 'API key nền tảng không liên kết cố định với một không gian làm việc; phạm vi thao tác vẫn bị giới hạn bởi quyền hạn được cấp.', + loading: 'Đang tải…', + empty: 'Chưa có API key nền tảng', + name: 'Tên', + namePlaceholder: 'Ví dụ: Tự động hoá vận hành trung tâm', + key: 'Khoá', + capability: 'Quyền hạn', + capabilityMore: '+{count}', + viewAllCapabilities: 'Xem tất cả quyền hạn', + capabilityHint: 'Quyền không gian làm việc áp dụng cho mục tiêu X-Tenant-ID; quyền hệ thống áp dụng cho các API tầng điều khiển.', + lastUsed: 'Dùng lần cuối', + createdAt: 'Ngày tạo', + actions: 'Thao tác', + never: 'Chưa từng', + systemCapabilityGroup: 'Tầng điều khiển nền tảng', + capabilities: { + tenantsRead: 'Xem không gian làm việc', + tenantsManage: 'Quản lý không gian làm việc', + settingsRead: 'Xem cài đặt hệ thống', + settingsManage: 'Quản lý cài đặt hệ thống', + runtimeRead: 'Xem runtime', + runtimeManage: 'Quản lý runtime', + auditRead: 'Xem Audit Log hệ thống' + }, + capabilityHints: { + tenantsRead: 'Xem danh sách, tìm kiếm và kiểm tra mọi không gian làm việc.', + tenantsManage: 'Tạo, cập nhật, xoá không gian làm việc và áp dụng cài đặt chung.', + settingsRead: 'Xem cài đặt runtime của nền tảng.', + settingsManage: 'Cập nhật và đặt lại cài đặt runtime của nền tảng.', + runtimeRead: 'Kiểm tra hàng đợi và chi tiết tác vụ.', + runtimeManage: 'Thử lại, chạy, huỷ hoặc xoá các tác vụ runtime.', + auditRead: 'Xem các sự kiện trong Audit Log của nền tảng.' + }, + createdTitle: 'Đã tạo API key nền tảng', + createdDescription: 'Sao chép và lưu trữ khoá này ngay. Giá trị đầy đủ sẽ không hiển thị lại.', + copy: 'Sao chép khoá', + copySuccess: 'Đã sao chép khoá', + deleteConfirm: 'Xoá “{name}”? Các quy trình tự động hoá dùng khoá này sẽ dừng hoạt động ngay lập tức.', + deleteSuccess: 'Đã xoá API key nền tảng', + deleteFailed: 'Không thể xoá API key nền tảng', + nameRequired: 'Vui lòng nhập tên', + capabilityRequired: 'Chọn ít nhất một quyền hạn', + loadFailed: 'Không thể tải danh sách API key nền tảng', + createFailed: 'Không thể tạo API key nền tảng' + }, + imageAttr: { + contain_text: { + label: 'Văn bản trong ảnh', + description: 'Mức độ văn bản mà bức ảnh chứa. Quyết định xem việc đọc văn bản có đáng để chạy một lượt OCR riêng hay không.', + values: { + none: { + label: 'Không có', + description: 'hoàn toàn không có văn bản' + }, + sparse: { + label: 'Rải rác', + description: 'một vài từ — logo, biển báo, một nhãn đơn lẻ' + }, + block: { + label: 'Khối văn bản', + description: 'một khối văn bản nội dung — ảnh chụp màn hình, bảng biểu, trang tài liệu' + } + } + }, + contain_data_visual: { + label: 'Trực quan hóa dữ liệu', + description: 'Bức ảnh có truyền tải dữ liệu dưới dạng biểu đồ, đồ thị, sơ đồ hoặc infographic hay không. Những ảnh này sẽ giữ lại nhãn trên luồng OCR ngay cả khi văn bản trông rải rác.', + values: { + true: { + label: 'Có', + description: 'biểu đồ, đồ thị hoặc sơ đồ có các giá trị được vẽ' + }, + false: { + label: 'Không', + description: 'ảnh chụp, hình vẽ, biểu tượng hoặc họa tiết trang trí' + } + } + } + } +} diff --git a/frontend/src/i18n/resolveDefaultLocale.ts b/frontend/src/i18n/resolveDefaultLocale.ts index c6b98f8ad7d..6929e5b75bc 100644 --- a/frontend/src/i18n/resolveDefaultLocale.ts +++ b/frontend/src/i18n/resolveDefaultLocale.ts @@ -1,4 +1,4 @@ -export const SUPPORTED_LOCALES = ['zh-CN', 'en-US', 'ru-RU', 'ko-KR', 'ja-JP'] as const +export const SUPPORTED_LOCALES = ['zh-CN', 'en-US', 'ru-RU', 'ko-KR', 'ja-JP', 'vi-VN'] as const export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number] export const BUILT_IN_DEFAULT: SupportedLocale = 'zh-CN' diff --git a/frontend/src/views/auth/Login.vue b/frontend/src/views/auth/Login.vue index 6dd7d4b5a1e..08c32299573 100755 --- a/frontend/src/views/auth/Login.vue +++ b/frontend/src/views/auth/Login.vue @@ -433,6 +433,7 @@ const inviteLookupLoading = ref(false) const languageOptions = [ { value: 'zh-CN', label: '简体中文', shortLabel: '中文', flag: '🇨🇳' }, { value: 'en-US', label: 'English', shortLabel: 'EN', flag: '🇺🇸' }, + { value: 'vi-VN', label: 'Tiếng Việt', shortLabel: 'VI', flag: '🇻🇳' }, { value: 'ru-RU', label: 'Русский', shortLabel: 'RU', flag: '🇷🇺' }, { value: 'ko-KR', label: '한국어', shortLabel: '한국어', flag: '🇰🇷' }, { value: 'ja-JP', label: '日本語', shortLabel: '日本語', flag: '🇯🇵' } diff --git a/frontend/src/views/settings/GeneralSettings.vue b/frontend/src/views/settings/GeneralSettings.vue index 1e444b04837..e3bdcae862c 100755 --- a/frontend/src/views/settings/GeneralSettings.vue +++ b/frontend/src/views/settings/GeneralSettings.vue @@ -21,6 +21,7 @@ > {{ $t('language.zhCN') }} {{ $t('language.enUS') }} + {{ $t('language.viVN') }} {{ $t('language.ruRU') }} {{ $t('language.koKR') }} {{ $t('language.jaJP') }} diff --git a/internal/handler/mcp_usage_instructions.go b/internal/handler/mcp_usage_instructions.go index 293b0c4799d..1527c805956 100644 --- a/internal/handler/mcp_usage_instructions.go +++ b/internal/handler/mcp_usage_instructions.go @@ -101,7 +101,7 @@ func (h *MCPServiceHandler) GenerateMCPUsageInstructions(c *gin.Context) { return } language := map[string]string{ - "zh-CN": "Simplified Chinese", "en-US": "English", "ja-JP": "Japanese", + "zh-CN": "Simplified Chinese", "en-US": "English", "vi-VN": "Vietnamese", "ja-JP": "Japanese", "ko-KR": "Korean", "ru-RU": "Russian", }[req.Language] if language == "" { diff --git a/internal/types/context_helpers.go b/internal/types/context_helpers.go index 35cdab26218..b2c25542cd5 100644 --- a/internal/types/context_helpers.go +++ b/internal/types/context_helpers.go @@ -408,6 +408,8 @@ func LanguageLocaleName(locale string) string { return "Chinese (Traditional)" case "en-US", "en", "en-GB": return "English" + case "vi-VN", "vi": + return "Vietnamese" case "ko-KR", "ko": return "Korean" case "ja-JP", "ja": diff --git a/internal/types/locale.go b/internal/types/locale.go index b3cc29e4200..aa67e916b6d 100644 --- a/internal/types/locale.go +++ b/internal/types/locale.go @@ -5,6 +5,7 @@ import "strings" var supportedLocales = map[string]struct{}{ "zh-CN": {}, "en-US": {}, + "vi-VN": {}, "ko-KR": {}, "ja-JP": {}, "ru-RU": {},