feat(settings): data-safe editors, deep-linked search, Data/About/Cost pages

- EditorModal loads once per path (a parent re-render no longer reloads the
  file over the user's typing), refuses Save after a failed load, opens a
  truncated (>256 KB) file read-only, and asks before overwriting a file
  that changed on disk or could not be re-read.
- Settings/Hooks editors unset only keys from the snapshot taken at Edit,
  warn when the file changed underneath, keep a renamed key's value, and
  refuse a new key named like a redacted one (env) or a read-only hook
  event, which used to replace the secret/hooks.
- Project scope shows its resolved folder and is disabled inside the
  plugin cache. Account-profile, pricing-row and pet deletes confirm;
  two-click actions disarm after 3 s; unsaved drafts ask before closing.
- Search indexes every Claude Code / Codex sub-tab, opens it via ?tab= and
  scrolls to + highlights the row; the active config tab is in the URL.
- General splits into General / Data / About; Pricing moves to a Cost
  group with one shared load; config tabs group as Content / Extensions /
  Config with arrow-key roving; Promise.allSettled per tab.
- Data: browser-preferences export/import (allowlisted keys), per-section
  reset, housekeeping dry-run first, clear-all behind a typed phrase.
  Server: purge days must be a whole number >= 1 (INVALID_PURGE_DAYS) and
  dry_run returns exactly what the real run would delete.
- Alerts can be edited; webhooks/alerts/remote-source failures toast;
  copies go through copyText; modals get dialog roles and useDialog.
- Sagi: Ctrl/Cmd+B only when shown and not typing, default spot clear of
  row controls, arrow keys move it, reduced motion honoured; the dead
  /run launch link goes to the workspace.
This commit is contained in:
2026-10-05 13:22:08 +07:00
parent 03f1673fce
commit 6715fbd971
68 changed files with 4817 additions and 1374 deletions
+12 -1
View File
@@ -64,7 +64,11 @@
"minutesStatus": "Kích hoạt khi agent ở trạng thái đã chọn mà không có hoạt động trong bấy nhiêu phút (agent bị kẹt).",
"totalTokens": "Kích hoạt khi tổng token của phiên (input + output + cache read + cache write) vượt số này. vd 1000000 = 1 triệu token.",
"cooldown": "Số giây tối thiểu giữa các cảnh báo lặp cho cùng quy tắc + phiên + agent. Tránh trùng lặp gây nhiễu. Mặc định 300 (5 phút); 0 = không có thời gian chờ."
}
},
"edit": "Sửa quy tắc",
"save": "Lưu quy tắc",
"typeFixed": "Không đổi được loại của quy tắc — hãy tạo quy tắc mới.",
"cooldownInvalid": "Nhập số giây nguyên (từ 0 trở lên)."
},
"feed": {
"title": "Luồng cảnh báo",
@@ -76,5 +80,12 @@
"emptyTitle": "Không có cảnh báo",
"emptyDescription": "Cảnh báo do các quy tắc của bạn kích hoạt sẽ hiển thị tại đây theo thời gian thực.",
"emptyUnacked": "Tất cả đã được xác nhận. Cảnh báo mới sẽ hiển thị tại đây khi được kích hoạt."
},
"errors": {
"loadRules": "Không tải được quy tắc cảnh báo: {{error}}",
"loadAlerts": "Không tải được cảnh báo: {{error}}",
"toggleRule": "Không thay đổi được quy tắc: {{error}}",
"deleteRule": "Không xoá được quy tắc: {{error}}",
"ack": "Không xác nhận được: {{error}}"
}
}
+58 -6
View File
@@ -10,7 +10,9 @@
"user": "Người dùng",
"project": "Dự án",
"projectLocal": "Dự án (cục bộ)",
"home": "Home"
"home": "Home",
"projectIs": "Dự án = {{path}}",
"projectInCache": "Dashboard đang chạy từ bộ nhớ đệm plugin của Claude Code, thư mục này bị thay mới mỗi lần cập nhật plugin — tệp dự án ghi vào đó sẽ mất. Đã tắt phạm vi Dự án."
},
"tabs": {
"overview": "Tổng quan",
@@ -150,7 +152,9 @@
"fileMissing": "(không có file settings trong phạm vi này)"
},
"settings": {
"fileMissing": "(không có file settings trong phạm vi này)"
"fileMissing": "(không có file settings trong phạm vi này)",
"structured": "Có cấu trúc",
"rawJson": "JSON thô"
},
"memory": {
"userScope": "Bộ nhớ người dùng",
@@ -217,7 +221,17 @@
"output-styles": "---\nname: my-style\ndescription: Mô tả kiểu xuất\n---\n\nChỉ thị về kiểu.\n",
"memory": "# Bộ nhớ dự án\n\nClaude đọc tệp này khi bắt đầu phiên.\n",
"auto-memory": "---\nname: my-fact\ndescription: Tóm tắt một dòng về sự kiện được ghi nhớ\nmetadata:\n type: feedback\n---\n\nNội dung cần ghi nhớ.\n"
}
},
"nameRequired": "Hãy nhập tên trước.",
"nameInvalid": "Chỉ dùng chữ, số, dấu chấm, gạch ngang hoặc gạch dưới (bắt đầu bằng chữ hoặc số, tối đa 64 ký tự).",
"loadError": "Không tải được tệp: {{message}}. Đã tắt Lưu để tệp không bị ghi đè.",
"truncatedReadOnly": "Tệp lớn hơn 256 KB nên chỉ tải được một phần, vì vậy chỉ mở ở chế độ đọc. Hãy sửa bằng trình soạn thảo của bạn.",
"changedOnDiskTitle": "Tệp đã thay đổi trên đĩa",
"changedOnDiskBody": "Có tiến trình khác đã sửa tệp này sau khi bạn mở. Lưu bây giờ sẽ thay thay đổi đó bằng nội dung của bạn (vẫn có bản sao lưu).",
"overwrite": "Ghi đè",
"unverifiedTitle": "Không kiểm tra được tệp trên đĩa",
"unverifiedBody": "Không đọc lại được tệp để kiểm tra xem có gì khác đã sửa nó từ khi bạn mở hay chưa. Vẫn lưu? (Bản sao lưu của tệp hiện tại vẫn được tạo.)",
"saveAnyway": "Vẫn lưu"
},
"backups": {
"title": "Bản sao lưu",
@@ -225,7 +239,7 @@
"viewLink": "Xem lịch sử sao lưu",
"openButton": "Bản sao lưu",
"subtitle": "Mỗi thao tác lưu / xoá đều ghi bản sao tới đây trước. Thư mục sao lưu nằm ngoài các vị trí Claude Code quét, nên không xuất hiện như mục thừa trong CLI.",
"restoreHint": "Khôi phục bằng cách đổi tên bản sao về vị trí cũ:",
"restoreHint": "Khôi phục bằng cách sao chép bản sao lưu về chỗ cũ (bản sao lưu vẫn được giữ):",
"size": "Kích thước",
"created": "Tạo lúc",
"type": "Loại",
@@ -263,7 +277,9 @@
"renameLabel": "Tên profile",
"renameHint": "Bấm để đổi tên",
"rename": "Đổi tên",
"renameSuccess": "Đã đổi tên thành \"{{name}}\"."
"renameSuccess": "Đã đổi tên thành \"{{name}}\".",
"deleteConfirmTitle": "Xóa hồ sơ “{{name}}”?",
"deleteConfirmBody": "Thao tác này xóa thông tin đăng nhập đã lưu (OAuth) của tài khoản này. Muốn dùng lại, bạn phải chạy `claude auth login` và lưu lại một lần nữa."
},
"explain": {
"hooks": {
@@ -385,6 +401,42 @@
"settingsBadJson": "Giá trị của {{key}} không phải JSON hợp lệ.",
"settingsSaved": "Đã lưu settings vào {{file}}.",
"settingsHelp": "Giá trị là JSON: \"opus\", true, 42, [\"a\"], {\"k\":1}. Chỉ những khóa bạn sửa mới được ghi; phần còn lại của file giữ nguyên.",
"settingsRedactedKeys": "Không sửa được ở đây vì giá trị đã bị che: {{keys}}"
"settingsRedactedKeys": "Không sửa được ở đây vì giá trị đã bị che: {{keys}}",
"hooksChangedBody": "Các hook này đã thay đổi trên đĩa kể từ khi bạn bắt đầu sửa. Lưu sẽ ghi phiên bản của bạn cho các sự kiện bạn đã sửa; các sự kiện mới thêm trong lúc đó vẫn được giữ.",
"settingsChangedBody": "Tệp cài đặt này đã thay đổi trên đĩa kể từ khi bạn bắt đầu sửa (CLI đang chạy ghi lại nó). Lưu sẽ ghi các khóa bạn đã đổi; các khóa mới thêm trong lúc đó vẫn được giữ.",
"settingsRedactedKey": "“{{key}}” chứa giá trị bí mật đã bị ẩn nên không sửa được ở đây — lưu sẽ thay giá trị thật bằng nội dung bạn nhập. Hãy sửa trực tiếp trong tệp.",
"hookReadOnlyEvent": "“{{event}}” đã có hook không sửa được ở đây (chỉ đọc) — một dòng mới cùng tên sẽ thay thế chúng. Hãy dùng tên sự kiện khác hoặc sửa trực tiếp trong tệp."
},
"tabGroups": {
"content": "Nội dung",
"extensions": "Mở rộng",
"config": "Cấu hình"
},
"currentConfig": {
"title": "Cấu hình hiện tại",
"setCount_one": "Đã đặt {{count}} tùy chọn · còn lại dùng mặc định",
"setCount_other": "Đã đặt {{count}} tùy chọn · còn lại dùng mặc định",
"default": "mặc định",
"groups": {
"model": "Mô hình & suy luận",
"output": "Đầu ra & hiển thị",
"session": "Phiên & nhập liệu"
},
"keys": {
"model": "Mô hình",
"effortLevel": "Mức nỗ lực",
"alwaysThinkingEnabled": "Luôn suy nghĩ",
"outputStyle": "Kiểu đầu ra",
"verbose": "Đầu ra chi tiết",
"theme": "Giao diện",
"language": "Ngôn ngữ",
"spinnerTipsEnabled": "Mẹo khi chờ",
"autoScrollEnabled": "Tự cuộn",
"autoCompactEnabled": "Tự nén ngữ cảnh",
"fileCheckpointingEnabled": "Điểm khôi phục tệp",
"editorMode": "Chế độ soạn thảo",
"preferredNotifChannel": "Thông báo",
"awaySummaryEnabled": "Tóm tắt khi vắng mặt"
}
}
}
+1 -1
View File
@@ -116,7 +116,7 @@
"title": "Bản sao lưu",
"subtitle": "Mỗi thao tác lưu / xoá đều ghi bản sao tới đây trước. Thư mục sao lưu nằm ngoài các vị trí CLI quét, nên không xuất hiện như mục thừa trong CLI.",
"empty": "Chưa có bản sao lưu - mỗi lần sửa hoặc xoá sẽ tạo bản sao có dấu thời gian.",
"restoreHint": "Khôi phục bằng cách đổi tên bản sao về vị trí cũ:"
"restoreHint": "Khôi phục bằng cách sao chép bản sao lưu về chỗ cũ (bản sao lưu vẫn được giữ):"
},
"snippet": {
"copy": "Sao chép",
+120 -20
View File
@@ -20,13 +20,46 @@
"upload": "Tải ảnh của bạn lên…",
"import": "Nhập bundle .codex-pet…",
"browse": "Tìm thêm trên codex-pets.net",
"settings": "Cài đặt pet…"
"settings": "Cài đặt pet…",
"hiddenToast": "Đã ẩn pet. Bật lại trong Cài đặt → Pet.",
"deleteTitle": "Xoá {{name}}?",
"deleteMessage": "Các tệp của pet sẽ bị xoá khỏi bản cài này. Pet nổi bật có thể tải lại; ảnh bạn tải lên sẽ mất hẳn.",
"deleteConfirm": "Xoá pet",
"reset": "Khôi phục mặc định",
"resetDone": "Đã khôi phục cài đặt pet về mặc định.",
"hiddenNote": "Pet đang ẩn — kích thước và bong bóng lời thoại sẽ áp dụng khi hiện lại.",
"resetMessage": "Hiện lại pet, bật bong bóng lời thoại, kích thước 68 px và dùng Sagi. Các pet bạn đã tải lên hoặc tải về vẫn được giữ.",
"previewCapped": "Bản xem trước vẽ ở 120 px; pet thật có kích thước {{size}} px."
},
"bubbles": "Bong bóng lời thoại",
"bubblesDesc": "Cho pet bình luận về các session của bạn trong bong bóng",
"sizeDesc": "{{min}}–{{max}} px; bản xem trước tối đa 120 px",
"chooseDesc": "Pet nổi bật lấy từ codex-pets.net và được tải về máy ở lần đầu bạn chọn. Lựa chọn và kích thước được lưu trong trình duyệt này.",
"uploadHint": "Ảnh (PNG, JPEG, GIF, WebP — không nhận SVG) hiển thị tĩnh; file .codex-pet.zip (pet.json + spritesheet.webp 1536×1872) chuyển động theo tâm trạng."
"uploadHint": "Ảnh (PNG, JPEG, GIF, WebP — không nhận SVG) hiển thị tĩnh; file .codex-pet.zip (pet.json + spritesheet.webp 1536×1872) chuyển động theo tâm trạng.",
"panel": {
"label": "Trợ lý Sagi",
"live": "Trực tuyến",
"offline": "Ngoại tuyến",
"close": "Đóng Sagi",
"statLive": "đang chạy",
"statWaiting": "đang chờ",
"statErrored": "lỗi",
"runClaude": "Chạy Claude",
"activity": "Hoạt động",
"sessions": "Phiên",
"errored": "Phiên lỗi",
"mute": "Tắt tiếng",
"unmute": "Bật tiếng",
"clearAlerts": "Xoá cảnh báo",
"askPlaceholder": "Hỏi Sagi… (vd: có lỗi nào không?)",
"ask": "Hỏi Sagi",
"send": "Gửi"
},
"bubbleDismiss": "Đóng",
"open": "Mở trợ lý Sagi",
"closeAvatar": "Đóng Sagi",
"avatarTitle": "Sagi — Ctrl/⌘+B · kéo hoặc dùng phím mũi tên để di chuyển · chuột phải để chọn pet",
"startFailed": "Không khởi động được phiên: {{error}}"
},
"pricing": {
"vendor": {
@@ -62,8 +95,8 @@
},
"cacheWrite5m": "Ghi bộ nhớ đệm (5m)",
"cacheWrite1h": "Ghi bộ nhớ đệm (1h)",
"fastInput": "Fast Input",
"fastOutput": "Fast Output",
"fastInput": "Đầu vào nhanh",
"fastOutput": "Đầu ra nhanh",
"showAll": "Hiện mọi model (thêm {{count}})",
"empty": {
"claude": "Chưa có giá model Claude. Nút Khôi phục mặc định sẽ đưa chúng trở lại.",
@@ -85,12 +118,17 @@
}
},
"autoBadge": "Tự động",
"autoBadgeTitle": "Tự cập nhật theo giá công bố (bảng giá LiteLLM, kiểm tra mỗi ngày). Sửa dòng này để giữ giá của riêng bạn."
"autoBadgeTitle": "Tự cập nhật theo giá công bố (bảng giá LiteLLM, kiểm tra mỗi ngày). Sửa dòng này để giữ giá của riêng bạn.",
"deleteConfirmTitle": "Xoá quy tắc giá {{pattern}}?",
"deleteConfirmBody": "Các phiên dùng mô hình này sẽ được tính giá theo quy tắc khớp khác, hoặc không được tính. Đồng bộ giá tự động sẽ KHÔNG thêm lại mẫu này; nếu đổi ý, hãy tự thêm lại."
},
"claudeHome": {
"title": "CLAUDE_HOME",
"description": "Thư mục gốc chứa dữ liệu phiên Claude Code. Thay đổi sẽ cập nhật ngay đường dẫn quét cho transcript và import.",
"placeholder": "/đường-dẫn/tới/claude-home"
"placeholder": "/đường-dẫn/tới/claude-home",
"note": "Không có gì bị di chuyển hay sao chép: AgentHub chỉ bắt đầu đọc transcript, cấu hình và hook từ thư mục mới. Phiên Cursor dùng cùng đường dẫn ~/.claude nên cũng theo thư mục này.",
"confirmTitle": "Đổi CLAUDE_HOME?",
"confirmBody": "Từ giờ AgentHub sẽ đọc phiên, cấu hình, skill và hook từ thư mục mới. Các phiên trong thư mục cũ sẽ không được nhập nữa cho tới khi bạn đổi lại. Không có gì bị di chuyển hay xoá."
},
"hooks": {
"title": "Cấu hình hook",
@@ -106,7 +144,16 @@
"description": "Dọn dẹp workspace trên toàn máy.",
"runHousekeeping": "Chạy dọn dẹp",
"dryRun": "Chạy thử (dry run)",
"gcResult": "Đã dọn {{reaped}} tiến trình, cắt {{capped}} log"
"gcResult": "Đã dọn {{reaped}} tiến trình, cắt {{capped}} log",
"explain": "Dọn dẹp sau các phiên của không gian làm việc: dừng các tiến trình máy chủ MCP mà phiên đã kết thúc còn để lại, và cắt bớt tệp nhật ký quá lớn. Không đụng tới kho mã của bạn.",
"preview": "Xem trước dọn dẹp",
"gcReapLine": "dừng tiến trình còn sót {{pid}}",
"gcCapLine": "cắt bớt {{path}} ({{size}})",
"gcNothing": "Không có gì để dọn — không còn tiến trình sót và không có nhật ký quá lớn.",
"gcConfirmTitle": "Chạy dọn dẹp?",
"gcConfirmBody": "Thao tác này sẽ:",
"gcMore": "và {{count}} mục khác",
"gcPreviewResult": "Chạy thử: sẽ dừng {{reaped}} tiến trình và cắt bớt {{capped}} tệp nhật ký"
},
"notifications": {
"awaitingInput": "Claude cần xác nhận",
@@ -127,7 +174,7 @@
"testFailed": "Không hiển thị được thông báo nào.",
"testLocal": "Trình duyệt chưa đăng ký push nên thông báo được hiện tại chỗ. Web Push cần origin bảo mật (localhost hoặc HTTPS) và service worker đã đăng ký.",
"testSent": "Đã gửi qua push — kiểm tra trung tâm thông báo.",
"testTitle": "Agent Monitor",
"testTitle": "AgentHub",
"title": "Thông báo",
"turnComplete": "Claude trả lời xong",
"sound": {
@@ -140,7 +187,16 @@
"pop": "Pop",
"alert": "Cảnh báo",
"forType": "Âm thanh cho loại này"
}
},
"scopeNote": "Các cài đặt thông báo này chỉ lưu trong trình duyệt này. Quy tắc cảnh báo và webhook bên dưới áp dụng cho toàn máy chủ: mọi người dùng bảng điều khiển này đều chịu ảnh hưởng.",
"insecureOrigin": "Trang này được phục vụ từ {{origin}}, không phải nguồn bảo mật. Trình duyệt chỉ hiện thông báo trên HTTPS hoặc localhost — hãy mở bảng điều khiển qua một trong hai cách đó.",
"unsupported": "Trình duyệt này không hỗ trợ thông báo.",
"deniedHelp": "Thông báo đang bị chặn cho trang này. Để cho phép lại, mở cài đặt trang (biểu tượng bên trái thanh địa chỉ), đặt Thông báo thành Cho phép, rồi tải lại trang.",
"pushFailed": "Thông báo đã bật nhưng không thiết lập được push ({{message}}). Thông báo vẫn hiện khi thẻ này đang mở.",
"reset": "Khôi phục mặc định",
"resetTitle": "Khôi phục cài đặt thông báo?",
"resetBody": "Mọi loại thông báo và âm thanh trở về mặc định. Trạng thái bật/tắt thông báo được giữ nguyên.",
"resetDone": "Đã khôi phục cài đặt thông báo."
},
"import": {
"title": "Nhập lịch sử",
@@ -230,7 +286,10 @@
"runCleanup": "Chạy dọn dẹp",
"nothingToClean": "Không có gì để dọn dẹp",
"abandonedResult": " phiên đã bị bỏ dở",
"purgedResult": " phiên đã xóa ({{events}} sự kiện, {{agents}} Agent)"
"purgedResult": " phiên đã xóa ({{events}} sự kiện, {{agents}} Agent)",
"wholeNumber": "Nhập số nguyên từ 1 trở lên (hoặc để trống để bỏ qua).",
"cleanupConfirmTitle": "Chạy dọn dẹp phiên?",
"cleanupConfirmBody": "Thao tác này đánh dấu {{abandoned}} phiên cũ là bị bỏ dở và xóa vĩnh viễn {{sessions}} phiên cũ cùng {{events}} sự kiện và {{agents}} tác tử. Phiên đã xóa không thể khôi phục — hãy xuất dữ liệu trước nếu có thể cần."
},
"danger": {
"title": "Vùng nguy hiểm",
@@ -238,7 +297,11 @@
"warning": "Thao tác này sẽ xóa toàn bộ phiên, Agent, sự kiện và dữ liệu token. Bạn chắc chứ?",
"yesClearAll": "Có, xóa tất cả",
"clearAllData": "Xóa toàn bộ dữ liệu",
"clearedResult": "Đã xóa {{count}} dòng"
"clearedResult": "Đã xóa {{count}} dòng",
"dialogTitle": "Xóa toàn bộ dữ liệu?",
"exportFirst": "Hãy xuất dữ liệu trước.",
"typeToConfirm": "Gõ “{{phrase}}” để xác nhận:",
"phrase": "xóa toàn bộ dữ liệu"
},
"about": {
"title": "Giới thiệu",
@@ -322,7 +385,11 @@
"deleteMessage": "Xóa \"{{name}}\"? Cảnh báo sẽ ngừng được gửi tới đích này. Không thể hoàn tác.",
"guideToggle": "Cách thiết lập {{provider}}",
"guideDocs": "Tài liệu chính thức của {{provider}}",
"guideStaleNote": "Giao diện thiết lập của nhà cung cấp thường thay đổi nên các bước này có thể đã lỗi thời - hãy luôn kiểm tra tài liệu chính thức."
"guideStaleNote": "Giao diện thiết lập của nhà cung cấp thường thay đổi nên các bước này có thể đã lỗi thời - hãy luôn kiểm tra tài liệu chính thức.",
"loadFailed": "Không tải được danh sách webhook: {{error}}",
"toggleFailed": "Không thay đổi được webhook: {{error}}",
"deleteFailed": "Không xoá được webhook: {{error}}",
"pickRule": "Hãy chọn ít nhất một quy tắc, hoặc chọn tất cả quy tắc."
},
"alertsHub": {
"title": "Cảnh báo",
@@ -493,7 +560,8 @@
"purgeData": "Đồng thời xóa các phiên đã nhập từ nguồn này (không thể hoàn tác)",
"deleteAndPurge": "Xóa + xóa dữ liệu",
"removeKeep": "Xóa (giữ dữ liệu)",
"remoteSourceBadgeTitle": "Được thu thập từ một máy từ xa"
"remoteSourceBadgeTitle": "Được thu thập từ một máy từ xa",
"fieldLabelPlaceholder": "Máy dev"
},
"cursorPathsNote": "Chỉ mang tính thông tin: phiên Cursor cũng được tính — Cursor tình cờ dùng cùng đường dẫn ~/.claude với Claude Code (cục bộ và trên máy từ xa đã đồng bộ).",
"aiRouter": {
@@ -579,7 +647,11 @@
"darkThemes": "Theme tối",
"lightThemes": "Theme sáng",
"active": "· đang dùng",
"default": "Mặc định"
"default": "Mặc định",
"reset": "Khôi phục mặc định",
"resetTitle": "Khôi phục giao diện?",
"resetBody": "Chế độ trở về Tối và cả hai chế độ trở về giao diện mặc định.",
"resetDone": "Đã khôi phục giao diện."
},
"gitCreds": {
"title": "Git credentials",
@@ -597,7 +669,9 @@
"colUser": "Tên đăng nhập",
"colSaved": "Đã lưu",
"empty": "Chưa lưu tài khoản git nào. Thanh git sẽ hỏi khi một host cần đăng nhập.",
"badUrl": "Nhập máy chủ dạng URL, ví dụ https://git.example.com"
"badUrl": "Nhập máy chủ dạng URL, ví dụ https://git.example.com",
"saved": "Đã lưu thông tin đăng nhập cho {{host}}.",
"loading": "Đang tải…"
},
"homeDir": {
"save": "Lưu",
@@ -660,7 +734,11 @@
"missing": "File này chưa có",
"save": "Lưu",
"close": "Đóng",
"saved": "Đã lưu. Bản sao lưu: {{backup}}"
"saved": "Đã lưu. Bản sao lưu: {{backup}}",
"defaultModelSaved": "Đã lưu mô hình mặc định.",
"staleBody": "Tệp đã thay đổi trên đĩa kể từ lúc bạn mở nên chưa lưu gì. Hãy sao chép bản của bạn nếu cần, rồi tải lại.",
"copyMine": "Sao chép bản của tôi",
"reloadDiscard": "Tải lại (bỏ bản của tôi)"
},
"settingsNav": {
"label": "Các mục cài đặt",
@@ -669,12 +747,13 @@
"general": "Chung",
"agents": "Tác tử",
"routing": "Định tuyến",
"git": "Git"
"git": "Git",
"cost": "Chi phí"
},
"section": {
"general": {
"title": "Chung",
"description": "Dọn dẹp workspace, dữ liệu và thông tin."
"description": "Ngôn ngữ hiển thị của bảng điều khiển."
},
"appearance": {
"title": "Giao diện",
@@ -718,12 +797,23 @@
"worktrees": {
"title": "Worktree",
"description": "Những git worktree chưa theo dõi được gợi ý khi thêm thư mục cho workspace."
},
"data": {
"title": "Dữ liệu",
"description": "Tổng quan chi phí và cơ sở dữ liệu, nhập, nguồn từ xa, xuất, dọn dẹp và vùng nguy hiểm."
},
"about": {
"title": "Giới thiệu",
"description": "Phiên bản máy chủ, thời gian hoạt động và môi trường chạy."
}
}
},
"backPrevious": "Quay lại",
"unknownSection": "Không có trang cài đặt “{{section}}” — đang hiển thị trang Chung."
},
"search": {
"placeholder": "Tìm cài đặt",
"noMatch": "Không có cài đặt nào khớp “{{query}}”."
"noMatch": "Không có cài đặt nào khớp “{{query}}”.",
"results": "Kết quả tìm kiếm"
},
"worktrees": {
"title": "Gợi ý worktree",
@@ -751,5 +841,15 @@
"copyPath": "Sao chép đường dẫn",
"enable": "Bật",
"disable": "Tắt"
},
"prefsBackup": {
"title": "Tùy chọn của trình duyệt này",
"description": "Giao diện, ngôn ngữ, cài đặt thông báo, thú cưng, thanh bên và bố cục không gian làm việc được lưu trong trình duyệt này. Lưu chúng ra tệp để chuyển sang trình duyệt khác, hoặc khôi phục từ tệp.",
"export": "Xuất tùy chọn",
"import": "Nhập tùy chọn…",
"importTitle": "Nhập tùy chọn?",
"importBody": "Tùy chọn trong tệp sẽ thay thế tùy chọn của trình duyệt này, sau đó trang tải lại.",
"imported": "Đã nhập {{count}} tùy chọn. Đang tải lại…",
"badFile": "Tệp này không phải tệp tùy chọn của AgentHub."
}
}
+4 -1
View File
@@ -27,5 +27,8 @@
"pluginUpdating": "Đang tải bản plugin mới và cài lại runtime — mất vài phút, trang sẽ tự reload khi server mới lên...",
"lastPluginUpdateFailed": "Lần cập nhật plugin trước thất bại ở bước \"{{step}}\": {{error}} — chạy /agenthub-update trong Claude Code để khắc phục.",
"restartingShort": "Đang khởi động lại…",
"installedTitle": "Đã cài bản {{version}} nhưng chưa chạy"
"installedTitle": "Đã cài bản {{version}} nhưng chưa chạy",
"later": "Để sau",
"skipVersion": "Bỏ qua phiên bản này",
"skipVersionHint": "Không hỏi lại về phiên bản này; phiên bản mới hơn vẫn sẽ được thông báo."
}