diff --git a/frontend/package.json b/frontend/package.json
index 6df7b260b..7ec195924 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -9,9 +9,10 @@
"lint": "eslint .",
"preview": "vite preview",
"test": "vitest",
- "test:run": "vitest run",
+ "test:run": "vitest run && npm run check:i18n",
"test:coverage": "vitest run --coverage",
- "test:ui": "vitest --ui"
+ "test:ui": "vitest --ui",
+ "check:i18n": "node scripts/check-i18n-parity.mjs"
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
diff --git a/frontend/scripts/check-i18n-parity.mjs b/frontend/scripts/check-i18n-parity.mjs
new file mode 100644
index 000000000..ffc6cdb14
--- /dev/null
+++ b/frontend/scripts/check-i18n-parity.mjs
@@ -0,0 +1,174 @@
+#!/usr/bin/env node
+// Verifies parity across locale files (en / zh-CN / zh-TW):
+// 1. Leaf-key sets are identical
+// 2. Each leaf's {{placeholder}} set is identical
+// 3. Plural suffixes: every en key ending in _plural / _one / _other must
+// exist in every other locale, and other locales must not introduce an
+// _one key that en does not have.
+// Malformed input (missing `export default`, parse errors, non-string leaves,
+// unsupported property kinds) fails loudly instead of silently passing the gate.
+// Exits 1 with a diagnostic report on any failure, else exits 0.
+
+import fs from 'node:fs';
+import path from 'node:path';
+import url from 'node:url';
+
+const scriptDir = path.dirname(url.fileURLToPath(import.meta.url));
+const frontendDir = path.resolve(scriptDir, '..');
+const localesDir = path.join(frontendDir, 'src/i18n/locales');
+const tsPath = path.join(frontendDir, 'node_modules/typescript/lib/typescript.js');
+
+const tsModule = await import(url.pathToFileURL(tsPath).href);
+const ts = tsModule.default ?? tsModule;
+
+function collectLeaves(node, prefix, leaves) {
+ if (!ts.isObjectLiteralExpression(node)) return;
+ for (const prop of node.properties) {
+ if (!ts.isPropertyAssignment(prop)) {
+ console.error(
+ `Unsupported property kind ${ts.SyntaxKind[prop.kind]} at "${prefix}" ` +
+ `(locale files must use plain \`key: value\` assignments — no spread, shorthand, methods, or accessors).`,
+ );
+ process.exit(1);
+ }
+ let name;
+ if (ts.isIdentifier(prop.name)) name = prop.name.text;
+ else if (ts.isStringLiteral(prop.name) || ts.isNoSubstitutionTemplateLiteral(prop.name)) name = prop.name.text;
+ else if (ts.isComputedPropertyName(prop.name)) {
+ console.error(`ComputedPropertyName not allowed in locale file at path "${prefix}"`);
+ process.exit(1);
+ } else {
+ console.error(`Unsupported property-name kind ${ts.SyntaxKind[prop.name.kind]} at "${prefix}"`);
+ process.exit(1);
+ }
+ const p = prefix ? `${prefix}.${name}` : name;
+ if (ts.isObjectLiteralExpression(prop.initializer)) {
+ collectLeaves(prop.initializer, p, leaves);
+ } else {
+ const value = extractStringValue(prop.initializer, p);
+ leaves.set(p, value);
+ }
+ }
+}
+
+function extractStringValue(node, keyPath) {
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
+ if (ts.isTemplateExpression(node)) {
+ let out = node.head.text;
+ for (const span of node.templateSpans) {
+ out += '${' + span.expression.getText() + '}';
+ out += span.literal.text;
+ }
+ return out;
+ }
+ console.error(
+ `Non-string leaf at "${keyPath}" (kind=${ts.SyntaxKind[node.kind]}): ${node.getText()}\n` +
+ `Locale files must only contain string or template literals as leaf values.`,
+ );
+ process.exit(1);
+}
+
+function loadLocale(filePath) {
+ const src = fs.readFileSync(filePath, 'utf8');
+ const sf = ts.createSourceFile(filePath, src, ts.ScriptTarget.Latest, true);
+ if (sf.parseDiagnostics && sf.parseDiagnostics.length > 0) {
+ console.error(`${filePath}: ${sf.parseDiagnostics.length} parse error(s):`);
+ for (const d of sf.parseDiagnostics.slice(0, 10)) {
+ const msg = typeof d.messageText === 'string' ? d.messageText : d.messageText.messageText;
+ const { line, character } = sf.getLineAndCharacterOfPosition(d.start ?? 0);
+ console.error(` ${line + 1}:${character + 1} ${msg}`);
+ }
+ process.exit(1);
+ }
+ const leaves = new Map();
+ let foundExport = false;
+ ts.forEachChild(sf, (n) => {
+ if (ts.isExportAssignment(n)) {
+ foundExport = true;
+ collectLeaves(n.expression, '', leaves);
+ }
+ });
+ if (!foundExport) {
+ console.error(`${filePath}: no \`export default\` found — locale files must use \`export default { ... }\`.`);
+ process.exit(1);
+ }
+ if (leaves.size === 0) {
+ console.error(`${filePath}: \`export default\` resolved to zero leaves — file is empty or not a nested object.`);
+ process.exit(1);
+ }
+ return leaves;
+}
+
+const locales = {
+ en: loadLocale(path.join(localesDir, 'en.ts')),
+ 'zh-CN': loadLocale(path.join(localesDir, 'zh-CN.ts')),
+ 'zh-TW': loadLocale(path.join(localesDir, 'zh-TW.ts')),
+};
+
+let failed = false;
+const MAX_REPORT = 20;
+
+function reportList(label, items) {
+ if (items.length === 0) return;
+ failed = true;
+ console.error(`\n[${label}] (${items.length})`);
+ items.slice(0, MAX_REPORT).forEach((i) => console.error(` ${i}`));
+ if (items.length > MAX_REPORT) console.error(` ... and ${items.length - MAX_REPORT} more`);
+}
+
+// Check 1: key set equality
+const enKeys = new Set(locales.en.keys());
+for (const [code, map] of Object.entries(locales)) {
+ if (code === 'en') continue;
+ const keys = new Set(map.keys());
+ const missing = [...enKeys].filter((k) => !keys.has(k)).sort();
+ const extra = [...keys].filter((k) => !enKeys.has(k)).sort();
+ reportList(`${code}: missing keys vs en`, missing);
+ reportList(`${code}: extra keys vs en`, extra);
+}
+
+// Check 2: placeholder set equality per leaf
+const placeholderRe = /\{\{[^{}]+\}\}/g;
+for (const [code, map] of Object.entries(locales)) {
+ if (code === 'en') continue;
+ const mismatches = [];
+ for (const [key, enValue] of locales.en) {
+ const otherValue = map.get(key);
+ if (otherValue === undefined) continue;
+ const enPlaceholders = new Set((enValue.match(placeholderRe) ?? []));
+ const otherPlaceholders = new Set((otherValue.match(placeholderRe) ?? []));
+ const missingPh = [...enPlaceholders].filter((p) => !otherPlaceholders.has(p));
+ const extraPh = [...otherPlaceholders].filter((p) => !enPlaceholders.has(p));
+ if (missingPh.length || extraPh.length) {
+ mismatches.push(`${key}: en=${[...enPlaceholders].join(',') || '∅'} vs ${code}=${[...otherPlaceholders].join(',') || '∅'}`);
+ }
+ }
+ reportList(`${code}: placeholder mismatch vs en`, mismatches);
+}
+
+// Check 3: plural suffix presence + reverse _one guard
+for (const [code, map] of Object.entries(locales)) {
+ if (code === 'en') continue;
+ const pluralIssues = [];
+ for (const key of enKeys) {
+ if (key.endsWith('_plural') && !map.has(key)) pluralIssues.push(`missing _plural key: ${key}`);
+ if (key.endsWith('_one') && !map.has(key)) pluralIssues.push(`missing _one key: ${key}`);
+ if (key.endsWith('_other') && !map.has(key)) pluralIssues.push(`missing _other key: ${key}`);
+ }
+ for (const key of map.keys()) {
+ if (key.endsWith('_one') && !enKeys.has(key)) {
+ pluralIssues.push(`unexpected _one not present in en: ${key}`);
+ }
+ }
+ reportList(`${code}: plural key mismatch`, pluralIssues);
+}
+
+if (failed) {
+ console.error('\n❌ i18n parity check failed.');
+ process.exit(1);
+}
+
+console.log(`All locales in parity (en / zh-CN / zh-TW):`);
+for (const [code, map] of Object.entries(locales)) {
+ console.log(` ${code}: ${map.size} leaves`);
+}
diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts
index 24203813f..5787a1fed 100644
--- a/frontend/src/i18n/index.ts
+++ b/frontend/src/i18n/index.ts
@@ -10,6 +10,7 @@ import ja from './locales/ja';
import it from './locales/it';
import ptBR from './locales/pt-BR';
import zhCN from './locales/zh-CN';
+import zhTW from './locales/zh-TW';
const resources = {
en: { translation: en },
@@ -19,6 +20,7 @@ const resources = {
it: { translation: it },
'pt-BR': { translation: ptBR },
'zh-CN': { translation: zhCN },
+ 'zh-TW': { translation: zhTW },
};
i18n
@@ -27,7 +29,7 @@ i18n
.init({
resources,
fallbackLng: 'en',
- supportedLngs: ['en', 'de', 'fr', 'ja', 'it', 'pt-BR', 'zh-CN'],
+ supportedLngs: ['en', 'de', 'fr', 'ja', 'it', 'pt-BR', 'zh-CN', 'zh-TW'],
detection: {
// Order of detection methods
@@ -58,4 +60,5 @@ export const availableLanguages = [
{ code: 'it', name: 'Italian', nativeName: 'Italiano' },
{ code: 'pt-BR', name: 'Portuguese (Brazil)', nativeName: 'Português (Brasil)' },
{ code: 'zh-CN', name: 'Chinese (Simplified)', nativeName: '简体中文' },
+ { code: 'zh-TW', name: 'Chinese (Traditional)', nativeName: '繁體中文' },
];
diff --git a/frontend/src/i18n/locales/zh-CN.ts b/frontend/src/i18n/locales/zh-CN.ts
index 9cce82a0a..ea91cff64 100644
--- a/frontend/src/i18n/locales/zh-CN.ts
+++ b/frontend/src/i18n/locales/zh-CN.ts
@@ -566,6 +566,13 @@ export default {
uploadFirmware: '上传固件',
uploadFailed: '上传启动失败:{{error}}',
uploadedToast: '固件已上传!请在打印机屏幕上触发更新。',
+ availableVersions: '可用版本',
+ usable: '可用',
+ unavailable: '不可用',
+ installed: '已安装',
+ newerBadge: '较新',
+ olderBadge: '较旧',
+ currentBadge: '当前',
},
accessCodePlaceholder: '留空以保持当前值',
// ROI editor
@@ -1335,6 +1342,7 @@ export default {
network: '网络',
apiKeys: 'API 密钥',
virtualPrinter: '虚拟打印机',
+ spoolbuddy: 'SpoolBuddy',
failureDetection: '故障检测',
users: '身份验证',
backup: '备份',
@@ -1343,6 +1351,50 @@ export default {
twoFa: '双因素认证',
oidc: 'SSO / OIDC',
},
+ spoolbuddy: {
+ infoTitle: 'SpoolBuddy 设备',
+ infoBody: 'SpoolBuddy kiosk 通过心跳自动注册。如果设备不再使用,或守护进程崩溃遗留了陈旧的重复项,可在此注销。',
+ duplicatesTitle: '已注册 {{count}} 台设备',
+ duplicatesBody: 'kiosk 界面只使用最先注册的设备。如果其中有因崩溃遗留的陈旧重复项,请注销它——在线设备会在下次心跳时重新注册自己。',
+ empty: '尚未注册任何 SpoolBuddy 设备。',
+ online: '在线',
+ offline: '离线',
+ unregister: '注销',
+ unregisterSuccess: '设备已注销',
+ unregisterError: '注销设备失败',
+ confirmTitle: '注销 SpoolBuddy 设备?',
+ confirmBody: '将从数据库中移除 "{{hostname}}" ({{deviceId}})。如果设备在线,会在下次心跳时重新注册自己。',
+ ipAddress: 'IP 地址',
+ firmware: '固件',
+ lastSeen: '上次在线',
+ daemonUptime: '守护进程运行时间',
+ systemUptime: '系统运行时间',
+ never: '从未',
+ nfc: 'NFC',
+ scale: '秤',
+ cpuTemp: 'CPU 温度',
+ memory: '内存',
+ disk: '磁盘',
+ // Device actions
+ update: '更新',
+ updateConfirmTitle: '更新 SpoolBuddy 守护进程?',
+ updateConfirmBody: '对 "{{hostname}}" 触发软件更新?更新完成后守护进程将重启。',
+ restartBrowser: '重启浏览器',
+ restartBrowserConfirmTitle: '重启 kiosk 浏览器?',
+ restartBrowserConfirmBody: '在 "{{hostname}}" 上重启 kiosk 浏览器?显示将短暂黑屏。',
+ restartDaemon: '重启守护进程',
+ restartDaemonConfirmTitle: '重启 SpoolBuddy 守护进程?',
+ restartDaemonConfirmBody: '在 "{{hostname}}" 上重启 SpoolBuddy 守护进程?设备将离线几秒钟。',
+ reboot: '重启',
+ rebootConfirmTitle: '重启设备?',
+ rebootConfirmBody: '重启 "{{hostname}}"?设备将离线约一分钟。',
+ shutdown: '关机',
+ shutdownConfirmTitle: '关闭设备?',
+ shutdownConfirmBody: '关闭 "{{hostname}}"?您需要物理访问才能重新开机。',
+ commandConfirm: '确认',
+ commandQueued: '命令已加入队列',
+ commandError: '发送命令失败',
+ },
ldap: {
title: 'LDAP 认证',
enabledDesc: 'LDAP 认证已启用',
@@ -2292,6 +2344,20 @@ export default {
resetStep3: '他们可以为您设置一个临时密码',
resetStep4: '使用新密码登录并在设置中修改密码',
gotIt: '知道了',
+ resetPassword: {
+ title: '设置新密码',
+ subtitle: '请在下方输入并确认您的新密码。',
+ newPassword: '新密码',
+ newPasswordPlaceholder: '至少 8 个字符',
+ confirmPassword: '确认密码',
+ confirmPasswordPlaceholder: '重复输入新密码',
+ saving: '保存中…',
+ submit: '设置新密码',
+ backToLogin: '返回登录',
+ passwordsDoNotMatch: '密码不匹配',
+ passwordTooShort: '密码至少需要 8 个字符',
+ resetFailed: '密码重置失败。链接可能已过期。',
+ },
twoFA: {
title: '两步验证',
subtitle: '您的账户已启用两步验证。请在下方输入验证码。',
@@ -2792,7 +2858,7 @@ export default {
willBeExtracted: '将被解压',
filesExtracted: '已解压 {{count}} 个文件',
uploadComplete: '上传完成:{{succeeded}} 个成功',
- uploadFailed: '{{count}} 个失败',
+ uploadFailed: '上传失败',
zipFilesFailed: '{{count}} 个文件失败',
uploading: '上传中...',
changeLink: '更改链接...',
@@ -4825,6 +4891,19 @@ export default {
deviceInfo: '设备信息',
hostname: '主机',
uptime: '运行时间',
+ systemConfig: '后端与认证',
+ backendUrl: 'Bambuddy 后端 URL',
+ apiToken: 'API 令牌',
+ apiTokenPlaceholder: '输入 API 令牌',
+ saveConfig: '保存配置',
+ systemQueued: '配置已加入队列。',
+ nfcDiagnostic: 'NFC 诊断',
+ scaleDiagnostic: '秤诊断',
+ readTagDiagnostic: '读取标签诊断',
+ testNfc: '测试读卡器',
+ testScale: '测试精度',
+ testReadTag: '读取标签',
+ systemFieldsRequired: '后端 URL 为必填项。',
// Display tab
brightness: '亮度',
saved: '已保存',
diff --git a/frontend/src/i18n/locales/zh-TW.ts b/frontend/src/i18n/locales/zh-TW.ts
new file mode 100644
index 000000000..5e1865e4b
--- /dev/null
+++ b/frontend/src/i18n/locales/zh-TW.ts
@@ -0,0 +1,5061 @@
+export default {
+ // Navigation
+ nav: {
+ printers: '印表機',
+ archives: '歸檔',
+ queue: '佇列',
+ stats: '統計',
+ profiles: '設定檔案',
+ maintenance: '維護',
+ projects: '專案',
+ inventory: '耗材',
+ files: '檔案管理器',
+ notifications: '通知',
+ settings: '設定',
+ system: '系統',
+ collapseSidebar: '收起側邊欄',
+ expandSidebar: '展開側邊欄',
+ update: '更新',
+ updateAvailable: '有可用更新:v{{version}}',
+ updateAvailableBanner: '版本 {{version}} 已發布!',
+ viewUpdate: '檢視更新',
+ viewOnGithub: '在 GitHub 上檢視',
+ keyboardShortcuts: '鍵盤快捷鍵 (?)',
+ switchToLight: '切換到淺色模式',
+ switchToDark: '切換到深色模式',
+ smartSwitches: '智慧開關',
+ logout: '登出',
+ },
+
+ // Common
+ common: {
+ save: '儲存',
+ saving: '儲存中...',
+ cancel: '取消',
+ delete: '刪除',
+ edit: '編輯',
+ add: '新增',
+ close: '關閉',
+ confirm: '確認',
+ loading: '載入中...',
+ error: '錯誤',
+ success: '成功',
+ warning: '警告',
+ enabled: '已啟用',
+ disabled: '已停用',
+ yes: '是',
+ no: '否',
+ on: '開',
+ off: '關',
+ all: '全部',
+ none: '無',
+ search: '搜尋',
+ filter: '篩選',
+ sort: '排序',
+ refresh: '重新整理',
+ download: '下載',
+ upload: '上傳',
+ uploading: '上傳中...',
+ uploadFailed: '上傳失敗',
+ actions: '操作',
+ status: '狀態',
+ name: '名稱',
+ description: '描述',
+ date: '日期',
+ time: '時間',
+ hours: '小時',
+ minutes: '分鐘',
+ seconds: '秒',
+ days: '天',
+ enable: '啟用',
+ disable: '停用',
+ permissions: '權限',
+ noPrinters: '未設定印表機',
+ noData: '尚無資料',
+ linkNotFound: '未找到連結',
+ required: '必填',
+ optional: '可選',
+ dismiss: '關閉',
+ apply: '套用',
+ reset: '重設',
+ export: '匯出',
+ import: '匯入',
+ clear: '清除',
+ selectAll: '全選',
+ deselectAll: '取消全選',
+ noChange: '— 不更改 —',
+ unchanged: '未更改',
+ unassigned: '未分配',
+ unknown: '未知',
+ unknownError: '未知錯誤',
+ today: '今天',
+ tomorrow: '明天',
+ asap: '儘快',
+ overdue: '已逾期',
+ now: '現在',
+ collapse: '收起',
+ expand: '展開',
+ viewArchive: '檢視歸檔',
+ viewInFileManager: '在檔案管理器中檢視',
+ addedBy: '由 {{username}} 新增',
+ prints: '次列印',
+ more: '還有 {{count}} 個',
+ ascending: '升序',
+ descending: '降序',
+ back: '返回',
+ copy: '複製',
+ copied: '已複製!',
+ printer: '印表機',
+ remove: '移除',
+ type: '類型',
+ print: '列印',
+ rename: '重新命名',
+ move: '移動',
+ create: '建立',
+ duplicate: '複製',
+ left: '左',
+ right: '右',
+ },
+
+ // Printers page
+ printers: {
+ title: '印表機',
+ addPrinter: '新增印表機',
+ editPrinter: '編輯印表機',
+ deletePrinter: '刪除印表機',
+ printerName: '印表機名稱',
+ serialNumber: '序列號',
+ ipAddress: 'IP 位址 / 主機名稱',
+ accessCode: '存取碼',
+ model: '型號',
+ nozzleCount: '噴嘴數量',
+ autoArchive: '自動歸檔',
+ status: {
+ available: '可用',
+ idle: '空閒',
+ printing: '列印中',
+ paused: '已暫停',
+ offline: '離線',
+ problem: '故障',
+ error: '錯誤',
+ finished: '已完成',
+ unknown: '未知',
+ },
+ temperatures: {
+ nozzle: '噴嘴',
+ bed: '熱床',
+ chamber: '腔室',
+ },
+ progress: '{{percent}}% 完成',
+ timeRemaining: '剩餘 {{time}}',
+ deleteConfirm: '確定要刪除"{{name}}"嗎?',
+ maintenanceOk: '維護正常',
+ maintenanceWarning: '{{count}} 個警告',
+ maintenanceWarning_plural: '{{count}} 個警告',
+ maintenanceDue: '{{count}} 個到期',
+ maintenanceDue_plural: '{{count}} 個到期',
+ // Sort options
+ sort: {
+ name: '名稱',
+ status: '狀態',
+ model: '型號',
+ location: '位置',
+ ascending: '升序排列',
+ descending: '降序排列',
+ },
+ // Card size
+ cardSize: {
+ small: '小卡片',
+ medium: '中卡片',
+ large: '大卡片',
+ extraLarge: '超大卡片',
+ },
+ // Controls
+ hideOffline: '隱藏離線',
+ nextAvailable: '下一個可用',
+ powerOn: '開機',
+ offlinePrintersWithPlugs: '帶智慧插座的離線印表機',
+ noPrintersConfigured: '尚未設定印表機',
+ search: '搜尋印表機...',
+ noSearchResults: '沒有印表機符合您的搜尋或篩選條件',
+ filter: {
+ allStatuses: '所有狀態',
+ allLocations: '所有位置',
+ },
+ // Printer card
+ readyToPrint: '準備列印',
+ external: '外部',
+ extL: '外接左',
+ extR: '外接右',
+ deleteArchives: '刪除列印歸檔',
+ noLabel: '無標籤',
+ printPreview: '列印預覽',
+ width: '寬度',
+ height: '高度',
+ noObjectsFound: '未找到物件',
+ objectsLoadedOnPrintStart: '物件在列印開始時載入',
+ willBeSkipped: '將被跳過',
+ name: '名稱',
+ serialCannotBeChanged: '序列號無法更改',
+ locationHelp: '用於分組印表機和篩選佇列任務',
+ // WiFi signal strength
+ wifiSignal: {
+ veryWeak: '非常弱',
+ weak: '弱',
+ fair: '一般',
+ good: '良好',
+ excellent: '優秀',
+ },
+ // Maintenance
+ maintenanceUpToDate: '所有維護均已完成 - 點選檢視',
+ // Chamber light
+ chamberLightOn: '開啟腔室燈',
+ chamberLightOff: '關閉腔室燈',
+ // Files
+ files: '檔案',
+ browseFiles: '瀏覽印表機檔案',
+ // Smart plug
+ autoOffAfterPrint: '列印後自動關機',
+ autoOffExecuted: '已執行自動關機 - 開啟印表機以重設',
+ // HMS errors
+ hmsErrors: 'HMS 錯誤',
+ viewHmsErrors: '檢視 {{count}} 個 HMS 錯誤',
+ // Actions
+ resume: '繼續',
+ pause: '暫停',
+ stop: '停止',
+ camera: '攝影機',
+ skipObject: '跳過物件',
+ reconnect: '重新連線',
+ forceRefresh: '強制重新整理',
+ forceRefreshSuccess: '已請求重新整理',
+ mqttDebug: 'MQTT 偵錯',
+ printerInformation: '印表機資訊',
+ copyToClipboard: '複製',
+ copied: '已複製!',
+ state: '狀態',
+ wifiSignalLabel: 'Wi-Fi 訊號',
+ developerMode: '開發者模式',
+ enabled: '已啟用',
+ disabled: '已停用',
+ addedOn: '新增日期',
+ sdCard: 'SD 卡',
+ inserted: '已插入',
+ notInserted: '未插入',
+ totalPrintHours: '列印時長',
+ activeNozzle: '目前:{{nozzle}} 噴嘴',
+ nozzleRack: '噴嘴架',
+ nozzleDocked: '已停靠',
+ nozzleMounted: '已安裝',
+ nozzleActive: '使用中',
+ nozzleIdle: '空閒',
+ nozzleDiameter: '直徑',
+ nozzleType: '類型',
+ nozzleStatus: '狀態',
+ nozzleFilament: '耗材',
+ nozzleWear: '磨損',
+ nozzleMaxTemp: '最高溫度',
+ nozzleSerial: '序列號',
+ nozzleHardenedSteel: '硬化鋼',
+ nozzleStainlessSteel: '不鏽鋼',
+ nozzleTungstenCarbide: '碳化鎢',
+ nozzleFlow: '流量',
+ nozzleHighFlow: '高流量',
+ nozzleStandardFlow: '標準',
+ // Firmware
+ firmwareUpdate: '韌體更新',
+ firmwareInstructions: '在印表機觸控式螢幕上,前往',
+ firmwareNav: '導航到',
+ settings: '設定',
+ firmware: '韌體',
+ // Discovery
+ discoverPrinters: '發現印表機',
+ searching: '搜尋中...',
+ manualEntry: '手動輸入',
+ addFromCloud: '從雲端新增',
+ // Toast messages
+ toast: {
+ printerDeleted: '印表機已刪除',
+ missingSpoolAssignment: '已在{{printer}}上開始列印。以下料槽未分配耗材: {{slots}}',
+ printerAdded: '印表機已新增',
+ printerUpdated: '印表機已更新',
+ failedToDelete: '刪除印表機失敗',
+ failedToAdd: '新增印表機失敗',
+ failedToUpdate: '更新印表機失敗',
+ commandSent: '命令已傳送',
+ failedToSendCommand: '傳送命令失敗',
+ turnedOn: '{{name}} 已開啟',
+ failedToPowerOn: '開啟 {{name}} 失敗',
+ scriptTriggered: '腳本已觸發',
+ printStopped: '列印已停止',
+ printPaused: '列印已暫停',
+ printResumed: '列印已繼續',
+ referenceDeleted: '參考已刪除',
+ detectionAreaSaved: '檢測區域已儲存',
+ failedToRunScript: '執行腳本失敗',
+ failedToStopPrint: '停止列印失敗',
+ failedToPausePrint: '暫停列印失敗',
+ failedToResumePrint: '繼續列印失敗',
+ failedToControlChamberLight: '控制腔室燈失敗',
+ failedToSetSpeed: '設定列印速度失敗',
+ failedToUpdateSetting: '更新設定失敗',
+ failedToSkipObjects: '跳過物件失敗',
+ failedToRereadRfid: '重新讀取 RFID 失敗',
+ failedToCheckPlate: '檢查列印板失敗',
+ failedToUpdateLabel: '更新標籤失敗',
+ failedToDeleteReference: '刪除參考失敗',
+ failedToSaveDetectionArea: '儲存檢測區域失敗',
+ plateCheckEnabled: '列印板檢查已啟用',
+ plateCheckDisabled: '列印板檢查已停用',
+ calibrationSaved: '校準已儲存!',
+ calibrationFailed: '校準失敗',
+ rfidRereadInitiated: '已發起 RFID 重新讀取',
+ },
+ // Connection status
+ connection: {
+ connected: '已連線',
+ offline: '離線',
+ },
+ // Queue info
+ queue: {
+ inQueue: '佇列中有 {{count}} 個列印任務',
+ inQueue_plural: '佇列中有 {{count}} 個列印任務',
+ },
+ // Controls section
+ controls: '控制',
+ // RFID
+ rfid: {
+ reread: '重新讀取 RFID',
+ },
+ bedJog: {
+ title: '移動熱床',
+ bed: '熱床',
+ step: '步長 (mm)',
+ up: '熱床上移',
+ down: '熱床下移',
+ disabledWhilePrinting: '列印中已停用',
+ notHomedTitle: '印表機未歸零',
+ notHomedMessage: '自上次列印以來 Z 軸尚未歸零。請先歸零 Z 以確保安全定位,或者直接移動 — 軟限位將被繞過。',
+ homeZ: '歸零 Z',
+ moveAnyway: '強制移動',
+ homingStarted: 'Z 軸歸零中…',
+ },
+ // Permissions
+ permission: {
+ noAdd: '您沒有新增印表機的權限',
+ noEdit: '您沒有編輯印表機的權限',
+ noDelete: '您沒有刪除印表機的權限',
+ noControl: '您沒有控制印表機的權限',
+ noFiles: '您沒有存取印表機檔案的權限',
+ noAmsRfid: '您沒有重新讀取 AMS RFID 的權限',
+ noSmartPlugControl: '您沒有控制智慧插座的權限',
+ noCamera: '您沒有檢視攝影機的權限',
+ },
+ // Add/Edit modal
+ modal: {
+ addTitle: '新增印表機',
+ editTitle: '編輯印表機',
+ myPrinter: '我的印表機',
+ selectModel: '選擇型號...',
+ locationGroup: '位置 / 分組(可選)',
+ locationPlaceholder: '例如:工作室、辦公室、地下室',
+ autoArchiveLabel: '自動歸檔已完成的列印',
+ fromPrinterSettings: '來自印表機設定',
+ modelOptional: '型號(可選)',
+ saveChanges: '儲存更改',
+ },
+ // Skip objects
+ skipObjects: {
+ tooltip: '跳過物件',
+ onlyWhilePrinting: '跳過物件(僅在列印時)',
+ requiresMultiple: '跳過物件(需要2個以上物件)',
+ title: '跳過物件',
+ matchIdsInfo: '將 ID 與印表機螢幕上的 ID 進行對照',
+ printerShowsIds: '印表機螢幕上顯示列印板上物件的 ID',
+ skipSelected: '跳過所選',
+ skipping: '跳過中...',
+ noObjectsSelected: '未選擇物件',
+ selectObjectsToSkip: '選擇要從目前列印中跳過的物件',
+ skipped: '已跳過',
+ objectsSkipped: '物件已跳過',
+ activeCount: '{{count}} 個活躍',
+ waitForLayer: '等待第2層以上才能跳過物件(目前第 {{layer}} 層)',
+ skip: '跳過',
+ confirmTitle: '跳過物件?',
+ confirmMessage: '確定要跳過"{{name}}"嗎?此操作無法復原。',
+ },
+ // Confirm modals
+ confirm: {
+ deleteTitle: '刪除印表機',
+ deleteMessage: '確定要刪除"{{name}}"嗎?這將移除所有連線設定。',
+ deleteArchivesNote: '此印表機的所有列印歷史將被永久刪除。',
+ keepArchivesNote: '列印歷史將保留,但不再與此印表機連結。',
+ stopTitle: '停止列印',
+ stopMessage: '確定要停止"{{name}}"上的目前列印嗎?這將取消列印任務。',
+ stopButton: '停止列印',
+ pauseTitle: '暫停列印',
+ pauseMessage: '確定要暫停"{{name}}"上的目前列印嗎?',
+ pauseButton: '暫停列印',
+ resumeTitle: '繼續列印',
+ resumeMessage: '確定要繼續"{{name}}"上的列印嗎?',
+ resumeButton: '繼續列印',
+ powerOnTitle: '開啟印表機',
+ powerOnMessage: '確定要開啟"{{name}}"的電源嗎?',
+ powerOnButton: '開機',
+ powerOffTitle: '關閉印表機',
+ powerOffMessage: '確定要關閉"{{name}}"的電源嗎?',
+ powerOffWarning: '警告:"{{name}}"正在列印中!確定要關閉電源嗎?這將中斷列印並可能損壞印表機。',
+ powerOffButton: '關機',
+ },
+ // Bulk actions
+ bulk: {
+ select: '選擇',
+ selectAll: '全選',
+ selectByLocation: '按位置選擇',
+ selected: '已選擇{{count}}臺',
+ actions: {
+ stop: '停止',
+ pause: '暫停',
+ resume: '繼續',
+ clearPlate: '清除列印床',
+ clearHMS: '清除通知',
+ },
+ confirm: {
+ stopTitle: '停止{{count}}個列印任務',
+ stopMessage: '這將取消{{count}}臺印表機上的活動列印任務。此操作無法復原。',
+ stopButton: '全部停止',
+ pauseTitle: '暫停{{count}}個列印任務',
+ pauseMessage: '這將暫停{{count}}臺印表機上的活動列印任務。',
+ pauseButton: '全部暫停',
+ clearPlateTitle: '清除{{count}}個列印床',
+ clearPlateMessage: '這將清除{{count}}臺印表機的列印床,可能會觸發佇列中的任務。',
+ clearPlateButton: '全部清除',
+ },
+ success: '{{action}}已在{{count}}臺印表機上完成',
+ partial: '{{succeeded}}成功,{{failed}}失敗',
+ noneApplicable: '沒有選中的印表機處於適合此操作的狀態',
+ selectByState: '按狀態選擇',
+ },
+ // Discovery
+ discovery: {
+ title: '發現印表機',
+ searching: '搜尋中...',
+ scanning: '掃描中...',
+ scanProgress: '掃描中... {{scanned}}/{{total}}',
+ foundPrinters: '發現 {{count}} 臺印表機',
+ noPrintersFound: '未找到印表機',
+ noPrintersFoundSubnet: '在指定子網中未找到印表機。',
+ noPrintersFoundNetwork: '在網路上未找到印表機。',
+ allConfigured: '所有發現的印表機已設定完畢。',
+ alreadyAdded: '已新增',
+ select: '選擇',
+ manualEntry: '手動輸入',
+ addFromCloud: '從雲端新增',
+ subnetToScan: '要掃描的子網',
+ dockerNote: '偵測到 Docker 環境。請以 CIDR 格式輸入印表機所在子網。需要在 docker-compose.yml 中設定 network_mode: host。',
+ scanSubnet: '掃描子網查詢印表機',
+ discoverNetwork: '在網路上發現印表機',
+ scanningSubnet: '正在掃描子網查詢拓竹印表機...',
+ scanningNetwork: '正在掃描網路...',
+ serialRequired: '需要序列號',
+ unknown: '未知',
+ failedToStart: '啟動發現失敗',
+ },
+ // AMS Drying
+ drying: {
+ start: '開始乾燥',
+ stop: '停止乾燥',
+ temperature: '溫度',
+ duration: '時長',
+ hours: '小時',
+ timeRemaining: '剩餘 {{time}}',
+ active: '乾燥中',
+ notSupported: '不支援乾燥',
+ powerRequired: '連線AMS電源介面卡以啟用乾燥',
+ startingDrying: '正在啟動乾燥...',
+ stoppingDrying: '正在停止乾燥...',
+ rotateTray: '乾燥時旋轉料盤',
+ },
+ // Filaments section
+ filaments: '耗材',
+ // Camera
+ openCameraOverlay: '開啟攝影機疊加層',
+ openCameraWindow: '在新視窗中開啟攝影機',
+ // Firmware
+ firmwareUpdateAvailable: '韌體更新可用:{{current}} → {{latest}}',
+ firmwareUpToDate: '韌體 {{version}} — 已是最新',
+ firmwareUpdateButton: '更新',
+ // Plate detection
+ plateDetection: {
+ noPermission: '您沒有更新印表機的權限',
+ enabledClick: '列印板檢查已啟用 - 點選停用',
+ disabledClick: '列印板檢查已停用 - 點選啟用',
+ manageCalibration: '管理列印板檢測校準',
+ calibrationRequired: '需要校準',
+ calibrationInstructions: '請確保列印板完全空置,然後點選校準。',
+ calibrationDescription: '校準會拍攝空置列印板的參考影像。後續檢查將與此參考進行比較以檢測物體。',
+ calibrationTip: '提示:您最多可以為不同的列印板儲存5個校準。系統會在檢查時自動使用最佳匹配。',
+ plateEmpty: '列印板似乎是空的',
+ objectsDetected: '在列印板上偵測到物體',
+ confidence: '置信度',
+ difference: '差異',
+ analysisPreview: '分析預覽:',
+ analysisLegend: '綠色框 = 檢測區域,紅色覆蓋 = 與校準的差異',
+ savedReferences: '已儲存的參考 ({{count}}/{{max}})',
+ deleteReference: '刪除參考',
+ labelPlaceholder: '標籤...',
+ clickToEdit: '{{label}} - 點選編輯',
+ clickToAddLabel: '點選新增標籤',
+ },
+ // Speed
+ speed: {
+ title: '列印速度',
+ silent: '靜音 (50%)',
+ standard: '標準 (100%)',
+ sport: '運動 (124%)',
+ ludicrous: '瘋狂 (166%)',
+ },
+ airduct: {
+ title: '風道模式',
+ cooling: '製冷',
+ heating: '加熱',
+ },
+ noSdCard: '無SD',
+ door: {
+ open: '開',
+ closed: '關',
+ },
+ // Fans
+ fans: {
+ partCooling: '零件冷卻風扇',
+ auxiliary: '輔助風扇',
+ chamber: '腔室風扇',
+ },
+ // HMS errors
+ clickToViewHmsErrors: '點選檢視 HMS 錯誤',
+ estimatedCompletion: '預計完成時間',
+ plateNumber: '板 {{number}}',
+ slotOptions: '槽位選項',
+ // AMS hover popup
+ amsPopup: {
+ friendlyName: 'AMS 名稱',
+ friendlyNamePlaceholder: '例如 AMS 友好名稱',
+ serialNumber: '序列號',
+ firmwareVersion: '韌體',
+ save: '儲存',
+ clear: '清除',
+ noEditPermission: '您沒有重新命名 AMS 單元的權限',
+ },
+ // Firmware modal
+ firmwareModal: {
+ title: '韌體更新',
+ titleUpToDate: '韌體資訊',
+ currentVersion: '目前版本:',
+ latestVersion: '最新版本:',
+ releaseNotes: '發布說明',
+ checkingPrereqs: '正在檢查前提條件...',
+ sdCardReady: 'SD 卡已就緒。點選下方上傳韌體。',
+ uploadedSuccess: '韌體已上傳到 SD 卡!',
+ applyInstructions: '在印表機上套用更新:',
+ step1: '在印表機觸控式螢幕上,前往設定',
+ step2: '導航到韌體',
+ step3: '選擇從 SD 卡更新',
+ step4: '更新將需要 10-20 分鐘',
+ done: '完成',
+ starting: '啟動中...',
+ uploadFirmware: '上傳韌體',
+ uploadFailed: '上傳啟動失敗:{{error}}',
+ uploadedToast: '韌體已上傳!請在印表機螢幕上觸發更新。',
+ availableVersions: '可用版本',
+ usable: '可用',
+ unavailable: '不可用',
+ installed: '已安裝',
+ newerBadge: '較新',
+ olderBadge: '較舊',
+ currentBadge: '目前',
+ },
+ accessCodePlaceholder: '留空以保持目前值',
+ // ROI editor
+ roi: {
+ title: '檢測區域 (ROI)',
+ xStart: 'X 起點',
+ yStart: 'Y 起點',
+ width: '寬度',
+ height: '高度',
+ instruction: '調整檢測區域以聚焦到列印板。預覽中的綠色框顯示目前區域。',
+ },
+ developerModeWarning: '以下印表機未啟用開發者區域網路模式:{{names}}。某些功能可能無法使用。',
+ howToEnable: '如何啟用',
+ incompatibleFile: '此檔案是為 {{slicedFor}} 切片的,但該印表機是 {{printerModel}}',
+ dropNotPrintable: '只能列印 .gcode 和 .gcode.3mf 檔案',
+ dropToPrint: '拖放以列印',
+ cannotPrint: '印表機忙碌',
+ },
+
+ // Archives page
+ archives: {
+ title: '列印歸檔',
+ searchPlaceholder: '搜尋歸檔...',
+ filterByPrinter: '按印表機篩選',
+ filterByStatus: '按狀態篩選',
+ sortBy: '排序方式',
+ sortNewest: '最新優先',
+ sortOldest: '最舊優先',
+ sortName: '名稱',
+ sortDuration: '時長',
+ sortLargest: '最大優先',
+ sortSmallest: '最小優先',
+ sortSize: '大小',
+ noArchives: '未找到歸檔',
+ noArchivesSearch: '沒有匹配搜尋的歸檔',
+ originalPrintNotVisible: '原始列印不可見 - 請嘗試清除篩選條件',
+ noArchivesYet: '尚無歸檔',
+ prints: '條列印',
+ pagination: {
+ showing: '顯示',
+ to: '至',
+ of: '共',
+ show: '每頁',
+ page: '頁',
+ all: '全部',
+ },
+ loadingArchives: '載入歸檔中...',
+ releaseToUpload: '放開以上傳',
+ showAll: '顯示全部',
+ showFavoritesOnly: '僅顯示收藏',
+ gridView: '網格檢視',
+ listView: '列表檢視',
+ calendarView: '日曆檢視',
+ logView: '列印日誌',
+ manageTags: '管理標籤',
+ showFailedPrints: '顯示失敗的列印',
+ hideFailedPrints: '隱藏失敗的列印',
+ hideDuplicates: '隱藏重複項',
+ viewOriginalPrint: '點選檢視原始列印 (#{{id}})',
+ printTime: '列印時間',
+ filamentUsed: '耗材用量',
+ cost: '成本',
+ reprint: '重新列印',
+ preview: '預覽',
+ deleteArchive: '刪除歸檔',
+ deleteConfirm: '確定要刪除此歸檔嗎?',
+ favorite: '收藏',
+ unfavorite: '取消收藏',
+ viewDetails: '檢視詳情',
+ status: {
+ completed: '已完成',
+ failed: '失敗',
+ stopped: '已停止',
+ },
+ toast: {
+ source3mfAttached: '源 3MF 已附加:{{filename}}',
+ failedUploadSource3mf: '上傳源 3MF 失敗',
+ source3mfRemoved: '源 3MF 已移除',
+ failedRemoveSource3mf: '移除源 3MF 失敗',
+ f3dAttached: 'F3D 已附加:{{filename}}',
+ failedUploadF3d: '上傳 F3D 失敗',
+ f3dRemoved: 'F3D 已移除',
+ failedRemoveF3d: '移除 F3D 失敗',
+ timelapseAttached: '縮時攝影已附加:{{filename}}',
+ timelapseAlreadyAttached: '縮時攝影已附加',
+ noMatchingTimelapse: '未找到匹配的縮時攝影',
+ failedScanTimelapse: '掃描縮時攝影失敗',
+ failedAttachTimelapse: '附加縮時攝影失敗',
+ timelapseRemoved: '縮時攝影已移除',
+ failedRemoveTimelapse: '移除縮時攝影失敗',
+ timelapseUploaded: '縮時攝影已上傳:{{filename}}',
+ failedUploadTimelapse: '上傳縮時攝影失敗',
+ archiveDeleted: '歸檔已刪除',
+ failedDeleteArchive: '刪除歸檔失敗',
+ addedToFavorites: '已新增到收藏',
+ removedFromFavorites: '已從收藏中移除',
+ projectUpdated: '專案已更新',
+ failedUpdateProject: '更新項目失敗',
+ linkCopied: '連結已複製到剪貼簿',
+ failedCopyLink: '複製連結失敗',
+ photoDeleted: '照片已刪除',
+ failedDeletePhoto: '刪除照片失敗',
+ failedDeleteArchives: '刪除歸檔失敗',
+ failedUpdateFavorites: '更新收藏失敗',
+ exportDownloaded: '匯出已下載',
+ exportFailed: '匯出失敗',
+ },
+ menu: {
+ print: '列印',
+ schedule: '排程',
+ openInBambuStudio: '在切片軟體中開啟',
+ slice: '切片',
+ externalLink: '外部連結',
+ viewOnMakerWorld: '在 MakerWorld 上檢視',
+ preview3d: '3D 預覽',
+ viewTimelapse: '檢視縮時攝影',
+ scanForTimelapse: '掃描縮時攝影',
+ uploadTimelapse: '上傳縮時攝影',
+ removeTimelapse: '移除縮時攝影',
+ downloadSource3mf: '下載源 3MF',
+ uploadSource3mf: '上傳源 3MF',
+ replaceSource3mf: '替換源 3MF',
+ removeSource3mf: '移除源 3MF',
+ uploadF3d: '上傳 F3D',
+ replaceF3d: '替換 F3D',
+ downloadF3d: '下載 F3D',
+ removeF3d: '移除 F3D',
+ download: '下載',
+ copyDownloadLink: '複製下載連結',
+ qrCode: 'QR Code',
+ viewPhotos: '檢視照片',
+ viewPhotosCount: '檢視照片 ({{count}})',
+ projectPage: '專案頁面',
+ addToFavorites: '新增到收藏',
+ removeFromFavorites: '從收藏中移除',
+ edit: '編輯',
+ goToProject: '前往專案:{{name}}',
+ addToProject: '新增到專案',
+ removeFromProject: '從專案中移除',
+ loading: '載入中...',
+ noProjectsAvailable: '無可用專案',
+ select: '選擇',
+ deselect: '取消選擇',
+ delete: '刪除',
+ },
+ permission: {
+ noReprint: '您沒有重新列印此歸檔的權限',
+ noAddToQueue: '您沒有新增到佇列的權限',
+ noUpdateArchives: '您沒有更新歸檔的權限',
+ noUploadFiles: '您沒有上傳檔案的權限',
+ noDownload: '您沒有下載歸檔的權限',
+ noCopyLink: '您沒有複製下載連結的權限',
+ noDelete: '您沒有刪除此歸檔的權限',
+ noCreate: '您沒有建立歸檔的權限',
+ },
+ card: {
+ previousPlate: '上一個板',
+ nextPlate: '下一個板',
+ plateNumber: '板 {{index}}',
+ moreOptions: '右鍵檢視更多選項',
+ addToFavorites: '新增到收藏',
+ removeFromFavorites: '從收藏中移除',
+ cancelled: '已取消',
+ failed: '失敗',
+ duplicate: '重複',
+ duplicateTitle: '此模型之前已列印過',
+ openSource3mf: '在 Bambu Studio 中開啟源 3MF(右鍵檢視更多選項)',
+ downloadF3d: '下載 Fusion 360 設計檔案',
+ viewTimelapse: '檢視縮時攝影',
+ viewPhoto: '檢視 1 張照片',
+ viewPhotos: '檢視 {{count}} 張照片',
+ openFolder: '開啟資料夾:{{name}}',
+ slicedFile: '已切片檔案 - 可以列印',
+ sourceFile: '僅原始檔 - 無 AMS 對應可用',
+ gcode: 'GCODE',
+ source: '原始檔',
+ project: '專案:{{name}}',
+ estimated: '預計:{{time}}',
+ actual: '實際:{{time}}',
+ accuracy: '準確度:{{percent}}%',
+ filament: '{{weight}}g',
+ layer: '{{count}} 層',
+ layers: '{{count}} 層',
+ object: '{{count}} 個物件',
+ objects: '{{count}} 個物件',
+ slicedFor: '為 {{model}} 切片',
+ uploadedBy: '上傳者',
+ noPermissionReprint: '您沒有重新列印的權限',
+ noFileForReprint: '無可用的 3MF 檔案 — 列印紀錄時無法從印表機下載該檔案',
+ noPermissionEdit: '您沒有編輯歸檔的權限',
+ noPermissionDelete: '您沒有刪除歸檔的權限',
+ reprint: '重新列印',
+ schedulePrint: '排程列印',
+ schedule: '排程',
+ openInBambuStudio: '在切片軟體中開啟',
+ openInBambuStudioToSlice: '在切片軟體中開啟進行切片',
+ slice: '切片',
+ externalLink: '外部連結',
+ makerWorld: 'MakerWorld:{{designer}}',
+ viewProject: '檢視專案',
+ noExternalLink: '無外部連結',
+ preview3d: '3D 預覽',
+ download: '下載',
+ edit: '編輯',
+ delete: '刪除',
+ },
+ modal: {
+ deleteArchive: '刪除歸檔',
+ deleteConfirm: '確定要刪除"{{name}}"嗎?此操作無法復原。',
+ deleteButton: '刪除',
+ removeSource3mf: '移除源 3MF',
+ removeSource3mfConfirm: '確定要從"{{name}}"中移除源 3MF 檔案嗎?這將刪除原始切片專案檔案。',
+ removeButton: '移除',
+ removeF3d: '移除 F3D',
+ removeF3dConfirm: '確定要從"{{name}}"中移除 Fusion 360 設計檔案嗎?',
+ removeTimelapse: '移除縮時攝影',
+ removeTimelapseConfirm: '確定要從"{{name}}"中移除縮時攝影影片嗎?',
+ timelapse: '{{name}} - 縮時攝影',
+ selectTimelapse: '選擇縮時攝影',
+ selectTimelapseDesc: '未找到自動匹配。請選擇此列印的縮時攝影:',
+ deleteArchives: '刪除歸檔',
+ deleteArchivesConfirm: '確定要刪除 {{count}} 個歸檔嗎?此操作無法復原。',
+ deleteCount: '刪除 {{count}} 個',
+ },
+ page: {
+ title: '歸檔',
+ printsCount: '{{filtered}} / {{total}} 次列印',
+ dropFilesHere: '將 .3mf 檔案拖放到此處',
+ releaseToUpload: '放開以上傳',
+ only3mfSupported: '僅支援 .3mf 檔案',
+ close: '關閉',
+ selected: '已選擇 {{count}} 個',
+ selectAll: '全選',
+ tags: '標籤',
+ project: '專案',
+ favorite: '收藏',
+ delete: '刪除',
+ toggledFavorites: '已切換 {{count}} 個歸檔的收藏狀態',
+ failedUpdateFavorites: '更新收藏失敗',
+ archivesDeleted: '已刪除 {{count}} 個歸檔',
+ failedDeleteArchives: '刪除歸檔失敗',
+ photoDeleted: '照片已刪除',
+ failedDeletePhoto: '刪除照片失敗',
+ },
+ list: {
+ name: '名稱',
+ printer: '印表機',
+ date: '日期',
+ size: '大小',
+ actions: '操作',
+ hasTimelapse: '有縮時攝影',
+ },
+ log: {
+ date: '日期',
+ printName: '列印名稱',
+ printer: '印表機',
+ user: '使用者',
+ status: '狀態',
+ duration: '時長',
+ filament: '耗材',
+ allPrinters: '所有印表機',
+ allUsers: '所有使用者',
+ allStatuses: '所有狀態',
+ cancelled: '已取消',
+ skipped: '已跳過',
+ dateFrom: '從',
+ dateTo: '到',
+ noEntries: '未找到列印日誌條目',
+ showing: '顯示 {{count}} / {{total}} 條',
+ rowsPerPage: '行數',
+ page: '頁',
+ prev: '上一頁',
+ next: '下一頁',
+ clearLog: '清除日誌',
+ clearLogTitle: '清除列印日誌',
+ clearLogConfirm: '所有列印日誌條目將被永久刪除。歸檔和佇列項目不受影響。此操作無法復原。確定要繼續嗎?',
+ clearLogButton: '全部清除',
+ cleared: '已清除 {{count}} 條日誌',
+ clearFailed: '清除列印日誌失敗',
+ },
+ },
+
+ // Queue page
+ queue: {
+ title: '列印佇列',
+ subtitle: '排程和管理您的列印任務',
+ addToQueue: '新增到佇列',
+ // Print modal
+ print: '列印',
+ reprint: '重新列印',
+ schedulePrint: '排程列印',
+ editQueueItem: '編輯佇列項目',
+ printToPrinters: '列印到 {{count}} 臺印表機',
+ queueToPrinters: '佇列到 {{count}} 臺印表機',
+ queueSelectedPlates: '將 {{count}} 個熱床加入佇列',
+ selectAllPlates: '選擇全部 {{count}} 個熱床',
+ deselectAll: '取消全選',
+ printQueued: '已加入列印佇列',
+ itemsQueued: '{{count}} 個任務已加入佇列',
+ sending: '傳送中...',
+ sendingProgress: '傳送中 {{current}}/{{total}}...',
+ adding: '新增中...',
+ addingProgress: '新增中 {{current}}/{{total}}...',
+ savingProgress: '儲存中 {{current}}/{{total}}...',
+ clearQueue: '清空佇列',
+ clearHistory: '清除歷史',
+ emptyQueue: '佇列為空',
+ position: '位置',
+ scheduledTime: '排程時間',
+ moveUp: '上移',
+ moveDown: '下移',
+ startNow: '立即開始',
+ printingInProgress: '列印進行中...',
+ viewArchive: '檢視歸檔',
+ viewInFileManager: '在檔案管理器中檢視',
+ itemCount: '{{count}} 個項目',
+ itemCount_plural: '{{count}} 個項目',
+ dragToReorder: '拖曳以重新排序(僅限盡快)',
+ reorderHint: '位置僅影響"儘快"項目。排程項目按設定時間執行。',
+ sjf: {
+ label: 'SJF',
+ tooltip: '最短任務優先 — 排程器優先處理較短的列印任務',
+ },
+ addedBy: '由 {{name}} 新增',
+ nextInQueue: '佇列中的下一個',
+ clearPlate: '清理列印板並開始下一個',
+ clearPlateSuccess: '列印板已清理 — 準備進行下一個列印',
+ plateReady: '列印板已清理 — 準備進行下一個列印',
+ plateNumber: '板 {{index}}',
+ // Batch / quantity
+ quantity: '數量',
+ quantityHint: '建立 {{count}} 個佇列項目',
+ activeBatches: '活躍批次',
+ batchProgress: '已完成 {{completed}}/{{total}}',
+ cancelBatch: '取消剩餘',
+ batchCancelled: '已取消剩餘批次項目',
+ cancelBatchConfirmTitle: '取消批次',
+ cancelBatchConfirmMessage: '取消此批次中所有剩餘的待處理項目?',
+ batch: '批次',
+ // Sections
+ sections: {
+ currentlyPrinting: '正在列印',
+ queued: '佇列中',
+ history: '歷史',
+ },
+ // Status
+ status: {
+ pending: '等待中',
+ waiting: '等待中',
+ printing: '列印中',
+ paused: '已暫停',
+ completed: '已完成',
+ failed: '失敗',
+ skipped: '已跳過',
+ cancelled: '已取消',
+ },
+ // Summary cards
+ summary: {
+ printing: '列印中',
+ queued: '佇列中',
+ totalTime: '總佇列時間',
+ totalWeight: '總佇列重量',
+ history: '歷史',
+ },
+ // Filters
+ filter: {
+ allPrinters: '所有印表機',
+ unassigned: '未分配',
+ allStatus: '所有狀態',
+ allLocations: '所有位置',
+ any: '任意',
+ },
+ // Sort
+ sort: {
+ byPosition: '按位置排序',
+ byName: '按名稱排序',
+ byPrinter: '按印表機排序',
+ bySchedule: '按排程排序',
+ byDate: '按日期排序',
+ ascendingOldest: '升序(最舊優先)',
+ descendingNewest: '降序(最新優先)',
+ },
+ // Badges
+ badges: {
+ staged: '已暫存',
+ requiresPrevious: '需要前一個成功',
+ autoPowerOff: '自動關機',
+ gcodeInjection: 'G-code',
+ },
+ // Empty state
+ empty: {
+ title: '沒有排程的列印',
+ description: '從歸檔頁面使用右鍵選單中的"排程"選項來排程列印,或拖放檔案開始。',
+ },
+ // Time
+ time: {
+ asap: '儘快',
+ overdue: '已逾期',
+ now: '現在',
+ lessThanMinute: '不到一分鐘',
+ inMinutes: '{{count}} 分鐘後',
+ inHours: '{{count}} 小時後',
+ },
+ // Actions
+ actions: {
+ stopPrint: '停止列印',
+ startPrint: '開始列印',
+ requeue: '重新佇列',
+ },
+ // Bulk edit
+ bulkEdit: {
+ title: '編輯 {{count}} 個項目',
+ title_plural: '編輯 {{count}} 個項目',
+ description: '僅更改的設定將套用於所選項目。',
+ printer: '印表機',
+ noChange: '— 不更改 —',
+ queueOptions: '佇列選項',
+ staged: '暫存(手動開始)',
+ autoPowerOff: '列印後自動關機',
+ requirePrevious: '要求前一個成功',
+ printOptions: '列印選項',
+ bedLevelling: '熱床調平',
+ flowCalibration: '流量校準',
+ vibrationCalibration: '振動校準',
+ layerInspection: '首層檢查',
+ timelapse: '縮時攝影',
+ useAms: '使用 AMS',
+ applyChanges: '套用更改',
+ selectAll: '全選',
+ deselectAll: '取消全選',
+ selected: '已選擇 {{count}} 個',
+ editSelected: '編輯所選',
+ cancelSelected: '取消所選',
+ },
+ // Confirmations
+ confirm: {
+ cancelTitle: '取消排程列印',
+ cancelMessage: '確定要取消"{{name}}"嗎?',
+ stopTitle: '停止列印',
+ stopMessage: '確定要停止目前列印"{{name}}"嗎?這將取消印表機上的列印任務。',
+ removeTitle: '從歷史中移除',
+ removeMessage: '確定要從佇列歷史中移除"{{name}}"嗎?',
+ clearHistoryTitle: '清除歷史',
+ clearHistoryMessage: '確定要從歷史中移除所有 {{count}} 個項目嗎?',
+ cancelButton: '取消列印',
+ stopButton: '停止列印',
+ thisPrint: '此列印',
+ thisItem: '此項目',
+ },
+ // Toast messages
+ toast: {
+ cancelled: '佇列項目已取消',
+ cancelFailed: '取消項目失敗',
+ removed: '佇列項目已移除',
+ removeFailed: '移除項目失敗',
+ stopped: '列印已停止',
+ stopFailed: '停止列印失敗',
+ released: '列印已加入佇列',
+ startFailed: '開始列印失敗',
+ reorderFailed: '重新排序佇列失敗',
+ historyCleared: '已清除 {{count}} 條歷史紀錄',
+ clearHistoryFailed: '清除歷史失敗',
+ updateFailed: '更新項目失敗',
+ bulkCancelled: '已取消 {{count}} 個項目',
+ bulkCancelFailed: '批次取消項目失敗',
+ },
+ // Timeline view
+ timeline: {
+ listView: '列表',
+ timelineView: '時間線',
+ unassigned: '未分配',
+ noData: '當天沒有計畫的列印任務',
+ allDoneBy: '所有列印預計在 {{time}} 前完成',
+ staged: '暫存',
+ filterAll: '全部顯示',
+ filterPrinting: '列印中',
+ filterQueued: '佇列中',
+ time: {
+ anyMoment: '即將完成',
+ minutesLeft: '剩餘{{minutes}} 分鐘',
+ hoursLeft: '剩餘{{hours}}小時',
+ hoursMinutesLeft: '剩餘{{hours}}小時{{minutes}} 分鐘',
+ },
+ day: {
+ previous: '前一天',
+ next: '後一天',
+ today: '今天',
+ },
+ },
+ // Permissions
+ permissions: {
+ noStopPrint: '您沒有停止列印的權限',
+ noStartPrint: '您沒有開始列印的權限',
+ noEdit: '您沒有編輯此佇列項目的權限',
+ noCancel: '您沒有取消此佇列項目的權限',
+ noRequeue: '您沒有重新佇列的權限',
+ noRemove: '您沒有移除此佇列項目的權限',
+ noClearHistory: '您沒有清除所有歷史的權限',
+ noEditItems: '您沒有編輯佇列項目的權限',
+ noCancelItems: '您沒有取消佇列項目的權限',
+ },
+ },
+
+ backgroundDispatch: {
+ unknownFile: '未知檔案',
+ unknownPrinter: '未知印表機',
+ startingPrints: '正在開始列印',
+ progressSummary: '{{complete}}/{{total}} 完成 • 已分發:{{dispatched}} • 處理中:{{processing}}',
+ expandDetails: '展開分發詳情',
+ collapseDetails: '收起分發詳情',
+ dismissToast: '關閉分發通知',
+ cancelDispatchJob: '取消分發任務',
+ cancel: '取消',
+ cancelling: '取消中…',
+ status: {
+ dispatched: '已分發',
+ processing: '處理中',
+ completed: '已完成',
+ failed: '失敗',
+ cancelled: '已取消',
+ },
+ toast: {
+ cancellingUpload: '取消上傳中...',
+ cancelled: '分發已取消',
+ cancelFailed: '取消分發失敗',
+ completeWithFailures: '後台分發完成:{{completed}} 成功,{{failed}} 失敗',
+ completeSuccess: '後台分發完成:{{completed}} 成功',
+ printStartedRemaining: '{{completed}} 個列印已開始,{{remaining}} 個正在傳送...',
+ },
+ },
+
+ // Statistics page
+ stats: {
+ title: '儀表板',
+ subtitle: '拖曳小工具以重新排列。點選眼睛圖示隱藏。',
+ overview: '概覽',
+ totalPrints: '總列印次數',
+ successRate: '成功率',
+ totalPrintTime: '總列印時間',
+ printTime: '列印時間',
+ totalFilament: '總耗材用量',
+ filamentUsed: '耗材用量',
+ filamentCost: '耗材成本',
+ totalCost: '總成本',
+ energyUsed: '能耗',
+ energyCost: '能源成本',
+ energyWarmingUpTooltip: '能耗追蹤正在收集每小時快照。當所選範圍之前至少存在一個快照時,時間段合計將變得準確。早期數值可能偏低。',
+ averagePrintTime: '平均列印時間',
+ printsPerDay: '每日列印次數',
+ byPrinter: '按印表機',
+ printsByPrinter: '各印表機列印次數',
+ byMaterial: '按材料',
+ byMonth: '按月份',
+ last7Days: '最近 7 天',
+ last30Days: '最近 30 天',
+ last90Days: '最近 90 天',
+ allTime: '全部時間',
+ // Widgets
+ quickStats: '快速統計',
+ printActivity: '列印活動',
+ filamentTypes: '耗材類型',
+ filamentTrends: '耗材趨勢',
+ failureAnalysis: '失敗分析',
+ timeAccuracy: '時間準確度',
+ successful: '成功:',
+ failed: '失敗:',
+ perfectEstimate: '100% = 完美估計',
+ noTimeAccuracyData: '尚無時間準確度資料',
+ noFilamentData: '尚無耗材資料',
+ noPrinterData: '尚無印表機資料',
+ noPrintData: '尚無列印資料',
+ noPrintDataLast30Days: '最近 30 天無列印資料',
+ failureReasons: '失敗原因',
+ topFailureReasons: '主要失敗原因',
+ failedPrintsCount: '{{failed}} / {{total}} 次列印失敗',
+ lastWeekRate: '上週:{{rate}}%',
+ // Actions
+ resetLayout: '重設佈局',
+ recalculateCosts: '重新計算成本',
+ recalculateCostsHint: '使用目前耗材價格重新計算所有歸檔成本',
+ exportStats: '匯出統計',
+ exportAsCsv: '匯出為 CSV',
+ exportAsExcel: '匯出為 Excel',
+ hiddenCount: '{{count}} 個已隱藏',
+ // Toast
+ exportDownloaded: '匯出已下載',
+ exportFailed: '匯出失敗',
+ layoutReset: '佈局已重設',
+ recalculatedCosts: '已為 {{count}} 個歸檔重新計算成本',
+ recalculateFailed: '重新計算成本失敗',
+ // Loading
+ loadingStats: '載入統計資料中...',
+ // Permissions
+ noPermissionResetLayout: '您沒有重設佈局的權限',
+ noPermissionRecalculate: '您沒有重新計算成本的權限',
+ noPrintDataInRange: '所選範圍內無列印資料',
+ periodFilament: '期間耗材',
+ periodCost: '期間成本',
+ avgPerPrint: '每次列印平均',
+ usageOverTime: '隨時間的使用量',
+ filamentByWeight: '重量',
+ printDuration: '列印時長',
+ printerUtilization: '印表機利用率',
+ filamentSuccess: '按材料成功率',
+ printHabits: '列印習慣',
+ printTimeOfDay: '列印時段',
+ colorDistribution: '顏色分佈',
+ noColorData: '尚無顏色資料',
+ records: '紀錄',
+ longestPrint: '最長列印',
+ heaviestPrint: '最重列印',
+ mostExpensivePrint: '最貴列印',
+ busiestDay: '最忙碌的一天',
+ successStreak: '連續成功',
+ streakPrint: '連續列印',
+ streakPrints: '{{count}} 次連續列印',
+ printerStats: '印表機統計',
+ hours: '小時',
+ avgPrints: '平均列印',
+ noArchiveData: '尚無列印資料',
+ filamentByTime: '時間',
+ avgWeight: '平均重量',
+ avgTime: '平均時間',
+ filamentByPrints: '列印次數',
+ timeframe: {
+ today: '今天',
+ 'this-week': '本週',
+ 'this-month': '本月',
+ 'last-7': '最近 7 天',
+ 'last-30': '最近 30 天',
+ 'last-90': '最近 90 天',
+ 'this-year': '今年',
+ 'all-time': '全部時間',
+ custom: '自訂範圍',
+ from: '從',
+ to: '到',
+ },
+ allUsers: '所有使用者',
+ noUser: '無使用者(系統)',
+ filterByUser: '按使用者篩選',
+ },
+
+ // Maintenance page
+ maintenance: {
+ title: '維護',
+ overview: '概覽',
+ allOk: '所有維護均已完成',
+ dueCount: '{{count}} 項到期',
+ dueCount_plural: '{{count}} 項到期',
+ warningCount: '{{count}} 個警告',
+ warningCount_plural: '{{count}} 個警告',
+ totalPrintTime: '總列印時間',
+ nextMaintenance: '下次維護',
+ nothingDue: '無到期項目',
+ tasks: '任務',
+ lastPerformed: '上次執行',
+ interval: '間隔',
+ hoursRemaining: '剩餘 {{hours}} 小時',
+ hoursOverdue: '逾期 {{hours}} 小時',
+ markDone: '標記為完成',
+ performMaintenance: '執行維護',
+ history: '歷史',
+ noHistory: '無維護歷史',
+ editPrintHours: '編輯列印時間',
+ currentHours: '目前小時數',
+ // Tabs
+ statusTab: '狀態',
+ settingsTab: '設定',
+ // Status
+ overdueCount: '{{count}} 個逾期',
+ dueSoonCount: '{{count}} 個即將到期',
+ dueSoon: '即將到期',
+ allGood: '一切正常',
+ overdueBy: '逾期 {{duration}}',
+ dueIn: '{{duration}} 後到期',
+ timeLeft: '剩餘 {{duration}}',
+ // Duration formats
+ day: '1 天',
+ days: '{{count}} 天',
+ week: '1 週',
+ weeks: '{{count}} 週',
+ month: '1 個月',
+ months: '{{count}} 個月',
+ year: '1 年',
+ // Settings
+ maintenanceTypes: '維護類型',
+ maintenanceTypesDescription: '系統類型和您的自訂維護任務',
+ addCustomType: '新增自訂類型',
+ restoreDefaults: '恢復預設任務',
+ intervalType: '間隔類型',
+ intervalValue: '間隔 ({{type}})',
+ icon: '圖示',
+ documentationLink: '說明文件連結(可選)',
+ assignToPrinters: '分配給印表機',
+ selectAtLeastOnePrinter: '至少選擇一臺印表機',
+ addType: '新增類型',
+ custom: '自訂',
+ printHours: '列印小時數',
+ calendarDays: '日曆天數',
+ exampleName: '例如:更換 HEPA 過濾器',
+ viewDocumentation: '檢視說明文件',
+ timeBasedInterval: '基於時間的間隔',
+ // Interval overrides
+ intervalOverrides: '間隔覆蓋',
+ intervalOverridesDescription: '為特定印表機自訂間隔',
+ // Printer assignment
+ assignedToPrinters: '已分配給印表機:',
+ noPrintersAssigned: '未分配印表機',
+ addPrinterShort: '新增:',
+ printersAssignedClick: '已分配 {{count}} 臺印表機 - 點選管理',
+ removeFromPrinter: '從此印表機移除',
+ // Types
+ types: {
+ lubricateCarbonRods: '潤滑碳纖維杆',
+ lubricateRails: '潤滑線性導軌',
+ cleanNozzle: '清潔噴嘴/熱端',
+ checkBelts: '檢查皮帶張力',
+ cleanBuildPlate: '清潔列印板',
+ checkExtruder: '檢查擠出機齒輪',
+ checkCooling: '檢查冷卻風扇',
+ generalInspection: '綜合檢查',
+ cleanCarbonRods: '清潔碳纖維杆',
+ lubricateSteelRods: '潤滑鋼杆',
+ cleanSteelRods: '清潔鋼杆',
+ cleanLinearRails: '清潔線性導軌',
+ checkPtfeTube: '檢查 PTFE 管',
+ replaceHepaFilter: '更換 HEPA 過濾器',
+ replaceCarbonFilter: '更換活性炭過濾器',
+ lubricateLeftNozzleRail: '潤滑左噴嘴導軌',
+ },
+ // Toast
+ maintenanceComplete: '維護已標記為完成',
+ typeUpdated: '維護類型已更新',
+ typeDeleted: '維護類型已刪除',
+ defaultsRestored: '已恢復 {{count}} 個預設任務',
+ printHoursUpdated: '列印小時數已更新',
+ printerAssigned: '印表機已分配',
+ printerRemoved: '印表機已移除',
+ // Confirmation
+ deleteTypeConfirm: '刪除"{{name}}"?',
+ deleteSystemTypeTitle: '刪除預設維護任務?',
+ deleteSystemTypeMessage: '確定要刪除預設維護任務"{{name}}"嗎?',
+ // Permissions
+ noPermissionUpdate: '您沒有更新維護項目的權限',
+ noPermissionPerform: '您沒有執行維護的權限',
+ noPermissionEditTypes: '您沒有編輯維護類型的權限',
+ noPermissionDeleteTypes: '您沒有刪除維護類型的權限',
+ noPermissionEditHours: '您沒有編輯列印時間的權限',
+ noPermissionRemovePrinter: '您沒有移除印表機分配的權限',
+ noPermissionAssignPrinter: '您沒有分配印表機的權限',
+ noPermissionEditIntervals: '您沒有編輯間隔的權限',
+ // Configure link
+ configureSettings: '設定維護類型和間隔',
+ },
+
+ // Settings page
+ settings: {
+ title: '設定',
+ general: '通用',
+ // Tab names
+ tabs: {
+ general: '通用',
+ smartPlugs: '智慧插座',
+ notifications: '通知',
+ queue: '工作流程',
+ filament: '耗材',
+ network: '網路',
+ apiKeys: 'API 金鑰',
+ virtualPrinter: '虛擬印表機',
+ spoolbuddy: 'SpoolBuddy',
+ failureDetection: '故障檢測',
+ users: '身份驗證',
+ backup: '備份',
+ emailAuth: '信箱認證',
+ ldap: 'LDAP',
+ twoFa: '雙因素認證',
+ oidc: 'SSO / OIDC',
+ },
+ spoolbuddy: {
+ infoTitle: 'SpoolBuddy 裝置',
+ infoBody: 'SpoolBuddy kiosk 透過心跳自動註冊。如果裝置不再使用,或守護程式當機遺留了過時的重複項,可在此取消註冊。',
+ duplicatesTitle: '已註冊 {{count}} 台裝置',
+ duplicatesBody: 'kiosk 介面只使用最先註冊的裝置。如果其中有因當機遺留的過時重複項,請取消註冊它——線上裝置會在下次心跳時重新註冊自己。',
+ empty: '尚未註冊任何 SpoolBuddy 裝置。',
+ online: '線上',
+ offline: '離線',
+ unregister: '取消註冊',
+ unregisterSuccess: '裝置已取消註冊',
+ unregisterError: '取消註冊裝置失敗',
+ confirmTitle: '取消註冊 SpoolBuddy 裝置?',
+ confirmBody: '將從資料庫中移除 "{{hostname}}" ({{deviceId}})。如果裝置線上,會在下次心跳時重新註冊自己。',
+ ipAddress: 'IP 位址',
+ firmware: '韌體',
+ lastSeen: '上次線上',
+ daemonUptime: '守護程式執行時間',
+ systemUptime: '系統執行時間',
+ never: '從未',
+ nfc: 'NFC',
+ scale: '磅秤',
+ cpuTemp: 'CPU 溫度',
+ memory: '記憶體',
+ disk: '磁碟',
+ // Device actions
+ update: '更新',
+ updateConfirmTitle: '更新 SpoolBuddy 守護程式?',
+ updateConfirmBody: '對 "{{hostname}}" 觸發軟體更新?更新完成後守護程式將重新啟動。',
+ restartBrowser: '重新啟動瀏覽器',
+ restartBrowserConfirmTitle: '重新啟動 kiosk 瀏覽器?',
+ restartBrowserConfirmBody: '在 "{{hostname}}" 上重新啟動 kiosk 瀏覽器?顯示將短暫黑屏。',
+ restartDaemon: '重新啟動守護程式',
+ restartDaemonConfirmTitle: '重新啟動 SpoolBuddy 守護程式?',
+ restartDaemonConfirmBody: '在 "{{hostname}}" 上重新啟動 SpoolBuddy 守護程式?裝置將離線幾秒鐘。',
+ reboot: '重新開機',
+ rebootConfirmTitle: '重新開機?',
+ rebootConfirmBody: '重新開機 "{{hostname}}"?裝置將離線約一分鐘。',
+ shutdown: '關機',
+ shutdownConfirmTitle: '關閉裝置?',
+ shutdownConfirmBody: '關閉 "{{hostname}}"?您需要實體存取才能重新開機。',
+ commandConfirm: '確認',
+ commandQueued: '命令已加入佇列',
+ commandError: '傳送命令失敗',
+ },
+ ldap: {
+ title: 'LDAP 認證',
+ enabledDesc: 'LDAP 認證已啟用',
+ disabledDesc: 'LDAP 認證已停用',
+ disabledHint: '在下方設定並儲存 LDAP 設定,然後啟用。',
+ enabled: 'LDAP 認證已啟用',
+ disabled: 'LDAP 認證已停用',
+ feature1: '使用者可以使用 LDAP 憑據登入',
+ feature2: '本機管理員帳戶作為後備保留',
+ feature3: '登入時 LDAP 群組對應到 BamBuddy 群組',
+ serverConfig: 'LDAP 伺服器設定',
+ serverUrl: '伺服器 URL',
+ serverUrlHint: '使用 ldap:// 進行標準連線或 ldaps:// 進行 SSL 連線',
+ security: '安全',
+ securityHint: 'StartTLS 將普通連線升級為 TLS。LDAPS 從一開始就使用 TLS。',
+ bindDn: '繫結 DN(服務帳戶)',
+ bindPassword: '繫結密碼',
+ searchBase: '搜尋基礎 DN',
+ userFilter: '使用者搜尋過濾器',
+ userFilterHint: '{username} 替換為登入使用者名稱。OpenLDAP 使用 (uid={username})。',
+ autoProvision: '自動建立使用者',
+ autoProvisionHint: '首次 LDAP 登入時自動建立 BamBuddy 帳戶',
+ defaultGroup: '預設群組',
+ defaultGroupNone: '— 無(無復原)—',
+ defaultGroupHint: '當 LDAP 使用者透過身份驗證但不在任何已對應的 LDAP 群組中時分配的備援群組。留空以使未對應的使用者沒有權限。',
+ groupMapping: '群組對應(JSON)',
+ groupMappingHint: '將 LDAP 群組 DN 對應到 BamBuddy 群組。可用群組:',
+ testConnection: '測試連線',
+ settingsSaved: 'LDAP 設定已儲存',
+ errors: {
+ serverRequired: 'LDAP 伺服器 URL 為必填項',
+ searchBaseRequired: '搜尋基礎 DN 為必填項',
+ enableAuthFirst: '請先啟用認證',
+ configureLdapFirst: '請先儲存 LDAP 設定',
+ },
+ },
+ // Email settings
+ email: {
+ smtpSettings: 'SMTP 設定',
+ smtpHost: 'SMTP 伺服器',
+ smtpPort: 'SMTP 連接埠',
+ security: '安全',
+ authentication: '認證',
+ username: '使用者名稱',
+ password: '密碼',
+ fromEmail: '寄件信箱',
+ fromName: '寄件人名稱',
+ testConnection: '測試 SMTP 連線',
+ testRecipient: '測試收件信箱',
+ sendTest: '傳送測試郵件',
+ sending: '傳送中...',
+ save: '儲存設定',
+ saving: '儲存中...',
+ advancedAuth: '進階認證',
+ advancedAuthEnabled: '進階認證已啟用',
+ advancedAuthEnabledDesc: '基於信箱的使用者管理功能已啟用。新使用者將透過郵件收到自動產生的密碼,使用者可以透過忘記密碼功能重設密碼。',
+ advancedAuthDisabled: '進階認證已停用',
+ advancedAuthDisabledDesc: '啟用進階認證以啟用基於信箱的使用者管理功能。',
+ enable: '啟用',
+ disable: '停用',
+ feature1: '密碼自動產生並透過郵件傳送給新使用者',
+ feature2: '使用者可以使用使用者名稱或信箱登入',
+ feature3: '忘記密碼功能可用',
+ feature4: '管理員可以透過郵件重設使用者密碼',
+ // Error messages
+ errors: {
+ requiredFields: '請填寫所有必填欄位',
+ usernameRequired: '啟用認證時需要使用者名稱',
+ enterTestEmail: '請輸入測試信箱地址',
+ smtpServerAndEmail: '測試前請填寫 SMTP 伺服器和寄件信箱',
+ usernamePasswordRequired: '啟用認證時需要使用者名稱和密碼',
+ configureSmtpFirst: '請先設定並測試 SMTP 設定',
+ enableAuthFirst: '請先啟用身份驗證才能使用基於電子郵件的功能。',
+ },
+ // Success messages
+ success: {
+ settingsSaved: 'SMTP 設定儲存成功',
+ },
+ // Security options
+ securityOptions: {
+ starttls: 'STARTTLS(連接埠 587)',
+ ssl: 'SSL/TLS(連接埠 465)',
+ none: '無(連接埠 25)',
+ },
+ // Authentication options
+ authOptions: {
+ enabled: '已啟用',
+ disabled: '已停用',
+ },
+ },
+ appearance: '外觀',
+ notifications: '通知',
+ smartPlugs: '智慧插座',
+ spoolman: 'Spoolman',
+ updates: '更新',
+ language: '語言',
+ languageDescription: '選擇您的首選語言',
+ theme: '主題',
+ themeLight: '淺色',
+ themeDark: '深色',
+ themeSystem: '跟隨系統',
+ defaultView: '預設檢視',
+ defaultViewDescription: '開啟應用程式時顯示的頁面',
+ checkForUpdates: '檢查更新',
+ autoUpdate: '自動更新',
+ currentVersion: '目前版本',
+ latestVersion: '最新版本',
+ upToDate: '已是最新版本',
+ updateAvailable: '有可用更新',
+ // Notifications
+ notificationLanguage: '通知語言',
+ notificationLanguageDescription: '推送通知的語言',
+ bedCooledThreshold: '熱床冷卻閾值',
+ bedCooledThresholdDescription: '列印後熱床被視為已冷卻的溫度',
+ userNotificationsEnabled: '使用者通知',
+ userNotificationsEnabledDescription: '啟用使用者通知選單和列印任務事件的郵件通知。需要進階身份驗證。',
+ userNotificationsDisabledHint: '請啟用進階身份驗證以使用使用者通知。',
+ notificationProviders: '通知提供者',
+ addProvider: '新增提供者',
+ editProvider: '編輯提供者',
+ providerType: '提供者類型',
+ testNotification: '測試通知',
+ testSuccess: '測試通知傳送成功',
+ testFailed: '傳送測試通知失敗',
+ quietHours: '免打擾時間',
+ quietHoursDescription: '在此時間段內不傳送通知',
+ quietHoursStart: '開始',
+ quietHoursEnd: '結束',
+ events: {
+ title: '通知事件',
+ printStart: '列印開始',
+ printComplete: '列印完成',
+ printFailed: '列印失敗',
+ printStopped: '列印停止',
+ printProgress: '進度里程碑',
+ printProgressDescription: '在 25%、50%、75% 時通知',
+ printerOffline: '印表機離線',
+ printerError: '印表機錯誤',
+ filamentLow: '耗材不足',
+ maintenanceDue: '維護到期',
+ maintenanceDueDescription: '需要維護時通知',
+ },
+ // Smart Plugs
+ smartPlug: {
+ title: '智慧插座',
+ add: '新增智慧插座',
+ edit: '編輯智慧插座',
+ name: '名稱',
+ ipAddress: 'IP 位址',
+ linkedPrinter: '連結印表機',
+ autoOn: '自動開啟',
+ autoOnDescription: '列印開始時開啟',
+ autoOff: '自動關閉',
+ autoOffDescription: '列印完成後關閉',
+ offDelay: '關閉延遲',
+ offDelayMinutes: '列印後分鐘數',
+ offDelayTemp: '當噴嘴溫度低於',
+ currentState: '目前狀態',
+ turnOn: '開啟',
+ turnOff: '關閉',
+ },
+ // Filament Tracking Mode
+ filamentTracking: '耗材追蹤',
+ filamentTrackingDesc: '選擇如何追蹤您的耗材。您可以使用內建庫存或連線外部 Spoolman 伺服器。',
+ filamentChecks: '耗材檢查',
+ disableFilamentWarnings: '停用耗材警告',
+ disableFilamentWarningsDesc: '在列印或加入佇列時不顯示耗材不足警告',
+ preferLowestFilament: '優先使用剩餘最少的耗材',
+ preferLowestFilamentDesc: '當多個料盤匹配時,使用剩餘耗材最少的那個',
+ trackingModeBuiltIn: '內建庫存',
+ trackingModeBuiltInDesc: '包含 RFID 自動匹配和用量追蹤',
+ trackingModeSpoolmanDesc: '外部耗材管理伺服器',
+ builtInFeatureRfid: '自動檢測 AMS 中的拓竹 RFID 耗材',
+ builtInFeatureUsage: '追蹤每次列印的耗材消耗',
+ builtInFeatureCatalog: '管理耗材、顏色和 K 值設定檔案',
+ builtInFeatureThirdParty: '第三方耗材可分配到庫存耗材',
+ amsSyncButton: '從 AMS 同步重量',
+ amsSyncTitle: '從 AMS 同步耗材重量',
+ amsSyncMessage: '這將使用已連線印表機的目前 AMS 剩餘百分比值覆蓋所有庫存耗材重量。用於從損壞的重量資料中恢復。印表機必須線上。',
+ amsSyncing: '同步中...',
+ amsSyncSuccess: '已同步 {{synced}} 個耗材,跳過 {{skipped}} 個',
+ amsSyncError: '從 AMS 同步重量失敗',
+ // Spoolman settings
+ spoolmanUrl: 'Spoolman URL',
+ spoolmanUrlHint: 'Spoolman 伺服器的 URL(例如 http://localhost:7912)',
+ spoolmanConnected: '已連線',
+ spoolmanDisconnected: '未連線',
+ status: '狀態',
+ connect: '連線',
+ disconnect: '斷開',
+ howSyncWorks: '同步工作原理',
+ syncInfoRfidOnly: '僅同步帶有 RFID 的官方拓竹耗材',
+ syncInfoAutoCreate: '首次同步時自動在 Spoolman 中建立新耗材',
+ syncInfoThirdPartySkipped: '非拓竹耗材(第三方、重新填充的)將被跳過',
+ linkingExistingSpools: '連結現有耗材',
+ linkingExistingSpoolsDesc: '要將現有的 Spoolman 耗材連結到您的 AMS,請將滑鼠懸停在 AMS 槽位上並點選"連結到 Spoolman"。',
+ syncMode: '同步模式',
+ syncModeAuto: '自動',
+ syncModeManual: '僅手動',
+ syncModeAutoDesc: '偵測到更改時自動同步 AMS 資料',
+ syncModeManualDesc: '僅在手動觸發時同步',
+ syncAmsData: '同步 AMS 資料',
+ syncAmsDataDesc: '手動將印表機 AMS 資料同步到 Spoolman',
+ allPrinters: '所有印表機',
+ // Default printer
+ noDefaultPrinter: '無預設(每次詢問)',
+ // Sidebar
+ sidebarOrder: '側邊欄順序',
+ // Camera
+ saveThumbnails: '儲存縮圖',
+ captureFinishPhoto: '拍攝完成照片',
+ noPrintersConfigured: '未設定印表機',
+ // Archive settings
+ archiveMode: {
+ always: '始終建立歸檔條目',
+ never: '從不建立歸檔條目',
+ ask: '每次詢問',
+ },
+ // Updates
+ checkForUpdatesLabel: '檢查更新',
+ checkPrinterFirmware: '檢查印表機韌體',
+ includeBetaUpdates: '包含測試版本',
+ includeBetaUpdatesDesc: '檢查更新時通知測試版和預發布版本',
+ // Queue
+ enableRetry: '啟用重試',
+ // Home Assistant
+ homeAssistantDescription: '透過 Home Assistant 控制智慧插座',
+ environmentManagedLabel: '(環境變數管理)',
+ autoEnabledViaEnv: '透過環境變數自動啟用',
+ urlFromEnvReadOnly: '值由 HA_URL 環境變數設定(只讀)',
+ tokenFromEnvReadOnly: '值由 HA_TOKEN 環境變數設定(只讀)',
+ // MQTT
+ mqttConnectedTo: '已連線到',
+ // Prometheus
+ prometheusDescription: '以 Prometheus 格式暴露印表機資料',
+ // Smart plugs empty state
+ noSmartPlugsTitle: '未設定智慧插座',
+ noSmartPlugsDescription: '新增基於 Tasmota 的智慧插座以追蹤能耗並自動化電源控制。',
+ // Notifications empty state
+ noProvidersTitle: '未設定提供者',
+ noProvidersDescription: '新增提供者以接收警報。',
+ noTemplatesAvailable: '無可用範本。重新啟動後端以載入預設範本。',
+ // API permissions
+ apiPermissionView: '檢視印表機狀態和佇列',
+ apiPermissionEdit: '新增和移除列印佇列中的項目',
+ // API keys
+ apiKeysEmptyTitle: '無 API 金鑰',
+ apiKeysEmptyDescription: '建立 API 金鑰以與外部服務整合。',
+ // Users
+ noUsersFound: '未找到使用者',
+ noGroupsFound: '未找到群組',
+ noGroupsAvailable: '無可用群組',
+ passwordsDoNotMatch: '密碼不符',
+ systemGroupWarning: '系統群組名稱不可更改',
+ // Auth disabled
+ authDisabledTitle: '身份驗證已停用',
+ authDisabledFeature1: '需要登入才能存取系統',
+ authDisabledFeature2: '建立多個使用者並基於群組的權限管理',
+ authDisabledFeature3: '使用 50+ 個細粒度權限控制存取',
+ // User deletion
+ userHasCreated: '此使用者已建立:',
+ userItemsQuestion: '您想如何處理這些項目?',
+ deleteUserConfirm: '確定要刪除此使用者嗎?',
+ actionCannotBeUndone: '此操作無法復原。',
+ // Smart plugs
+ addFirstSmartPlug: '新增您的第一個智慧插座',
+ // Notifications
+ providers: '提供者',
+ log: '日誌',
+ testAll: '全部測試',
+ testResults: '測試結果',
+ testPassedCount: '{{count}} 個透過',
+ testFailedCount: '{{count}} 個失敗',
+ messageTemplates: '訊息範本',
+ messageTemplatesDescription: '自訂每個事件的通知訊息。',
+ // API Keys section
+ apiKeys: 'API 金鑰',
+ apiKeysDescription: '建立 API 金鑰用於外部整合和 Webhook。',
+ createKey: '建立金鑰',
+ apiKeyCreated: 'API 金鑰建立成功',
+ apiKeyCopyWarning: '請立即複製此金鑰 - 它不會再次顯示!',
+ useInApiBrowser: '在 API 瀏覽器中使用',
+ createNewApiKey: '建立新 API 金鑰',
+ keyName: '金鑰名稱',
+ keyNamePlaceholder: '例如:Home Assistant、OctoPrint',
+ readStatus: '讀取狀態',
+ readStatusDescription: '檢視印表機狀態和佇列',
+ manageQueue: '管理佇列',
+ manageQueueDescription: '新增和移除列印佇列中的項目',
+ controlPrinter: '控制印表機',
+ controlPrinterDescription: '暫停、繼續和停止列印',
+ unnamedKey: '未命名金鑰',
+ lastUsed: '上次使用',
+ read: '讀取',
+ control: '控制',
+ createFirstKey: '建立您的第一個金鑰',
+ webhookEndpoints: 'Webhook 端點',
+ webhookApiKeyHint: '在 X-API-Key 請求頭中使用您的 API 金鑰。',
+ webhook: {
+ getAllStatus: '獲取所有印表機狀態',
+ getSpecificStatus: '獲取特定印表機狀態',
+ addToQueue: '新增到列印佇列',
+ pausePrint: '暫停列印',
+ resumePrint: '繼續列印',
+ stopPrint: '停止列印',
+ },
+ apiBrowser: 'API 瀏覽器',
+ apiBrowserDescription: '瀏覽和測試所有可用的 API 端點。',
+ apiKeyForTesting: '測試用 API 金鑰',
+ apiKeyPlaceholder: '在此貼上您的 API 金鑰以測試需要認證的端點...',
+ apiKeyHint: '此金鑰將作為 X-API-Key 請求頭隨請求傳送。',
+ deleteApiKeyTitle: '刪除 API 金鑰',
+ deleteApiKeyMessage: '確定要刪除此 API 金鑰嗎?使用此金鑰的所有整合將停止工作。',
+ deleteKey: '刪除金鑰',
+ // Filament tab
+ amsDisplayThresholds: 'AMS 顯示閾值',
+ amsThresholdsDescription: '設定 AMS 濕度和溫度指示器的顏色閾值。',
+ humidity: '濕度',
+ goodGreen: '良好(綠色)',
+ fairOrange: '一般(橙色)',
+ aboveFairBad: '超過一般閾值顯示為紅色(差)',
+ fairAlsoDryingThreshold: '此閾值也用於觸發自動乾燥',
+ temperature: '溫度',
+ goodBlue: '良好(藍色)',
+ aboveFairHot: '超過一般閾值顯示為紅色(熱)',
+ historyRetention: '歷史保留',
+ keepSensorHistory: '保留感測器歷史',
+ historyRetentionDescription: '較舊的濕度和溫度資料將被自動刪除',
+ defaultPrintOptions: '預設列印選項',
+ defaultPrintOptionsDescription: '設定新列印的預設選項值。可在列印對話方塊中逐次覆蓋。',
+ defaultBedLevelling: '熱床調平',
+ defaultBedLevellingDesc: '列印前自動調平熱床',
+ defaultFlowCali: '流量校準',
+ defaultFlowCaliDesc: '校準擠出流量',
+ defaultVibrationCali: '振動校準',
+ defaultVibrationCaliDesc: '減少振紋偽影',
+ defaultLayerInspect: '首層檢測',
+ defaultLayerInspectDesc: 'AI首層檢測',
+ defaultTimelapse: '縮時攝影',
+ defaultTimelapseDesc: '錄製縮時攝影影片',
+ staggeredStart: '錯開啟動',
+ staggeredStartDescription: '多台印表機批次啟動時的預設群組大小與間隔。可在列印對話框中逐批覆寫。',
+ plateClear: '熱床清空確認',
+ requirePlateClear: '需要熱床清空確認',
+ requirePlateClearDescription: '啟用後,排程器會在已完成列印的印表機上啟動佇列列印之前,等待每臺印表機的熱床清空確認。對於物理驗證熱床的農場工作流,請停用此選項。',
+ gcodeInjection: 'G-code注入',
+ gcodeInjectionDescription: '為Farmloop、SwapMod、AutoClear和Printflow 3D等自動列印系統設定自訂G-code,在列印開始和/或結束時注入。程式碼片段按印表機型號設定,在佇列項目上啟用"注入G-code"時套用。',
+ gcodeInjectionNoPrinters: '未找到印表機。新增印表機以設定G-code程式碼片段。',
+ gcodeStartLabel: '開始G-code',
+ gcodeEndLabel: '結束G-code',
+ gcodeStartPlaceholder: '在列印開始前插入的G-code...',
+ gcodeEndPlaceholder: '在列印結束後追加的G-code...',
+ staggerGroupSize: '群組大小',
+ staggerGroupSizeHelp: '每個群組要同時啟動的印表機數量',
+ staggerInterval: '間隔(分鐘)',
+ staggerIntervalHelp: '每個群組啟動之間的延遲',
+ queueDrying: '自動乾燥',
+ queueDryingDescription: '在佇列列印之間,印表機空閒時自動乾燥AMS耗材。使用上方的濕度閾值觸發乾燥。',
+ queueDryingEnabled: '啟用自動乾燥',
+ queueDryingEnabledDescription: '當印表機空閒且濕度超過閾值時,自動啟動AMS乾燥',
+ queueDryingBlock: '等待乾燥完成',
+ queueDryingBlockDescription: '阻止列印佇列直到乾燥完成。關閉時,列印優先於乾燥。',
+ ambientDryingEnabled: '環境乾燥',
+ ambientDryingEnabledDescription: '當空閒印表機的濕度超過閾值時自動乾燥耗材,無需佇列列印。',
+ dryingPresets: '乾燥預設',
+ dryingPresetsDescription: '每種耗材類型的溫度和時長。AMS 2 Pro使用較低溫度,AMS-HT支援較高溫度。',
+ dryingFilament: '耗材',
+ printModal: '列印對話方塊',
+ expandCustomMapping: '預設展開自訂對應',
+ expandCustomMappingDescription: '列印到多臺印表機時,預設展開顯示每臺印表機的 AMS 對應',
+ // User management
+ authentication: '身份驗證',
+ authEnabledDescription: '您的實例已透過使用者身份驗證保護',
+ authDisabledDescription: '啟用以要求登入並管理使用者存取',
+ authDisabledMessage: '啟用身份驗證以建立使用者帳戶、管理權限並保護您的 Bambuddy 實例。',
+ enableAuthentication: '啟用身份驗證',
+ currentUser: '目前使用者',
+ changePassword: '修改密碼',
+ admin: '管理員',
+ users: '使用者',
+ addUser: '新增使用者',
+ groups: '群組',
+ addGroup: '新增群組',
+ system: '系統',
+ noDescription: '無描述',
+ userCount: '{{count}} 個使用者',
+ permissionCount: '{{count}} 個權限',
+ createUser: '建立使用者',
+ username: '使用者名稱',
+ enterUsername: '輸入使用者名稱',
+ password: '密碼',
+ enterPassword: '輸入密碼(至少 6 個字元)',
+ confirmPassword: '確認密碼',
+ confirmPasswordPlaceholder: '確認密碼',
+ // Title tooltips
+ viewReleaseOnGitHub: '在 GitHub 上檢視發布',
+ turnAllPlugsOn: '開啟所有插座',
+ turnAllPlugsOff: '關閉所有插座',
+ // Modal: Clear logs
+ clearNotificationLogs: '清除通知日誌',
+ clearLogsMessage: '這將永久刪除所有 30 天前的通知日誌。此操作無法復原。',
+ clearLogs: '清除日誌',
+ // Modal: Reset UI
+ resetUiPreferences: '重設 UI 偏好',
+ resetUiPreferencesMessage: '這將重設所有 UI 偏好為預設值:側邊欄順序、主題、儀表板佈局、檢視模式和排序偏好。您的印表機、歸檔和伺服器設定不會受到影響。清除後頁面將重新載入。',
+ resetPreferences: '重設偏好',
+ // Modal: Delete group
+ deleteGroupTitle: '刪除群組',
+ deleteGroupMessage: '確定要刪除此群組嗎?此群組中的使用者將失去這些權限。',
+ deleteGroup: '刪除群組',
+ // Modal: Disable auth
+ disableAuthenticationTitle: '停用身份驗證',
+ disableAuthenticationMessage: '確定要停用身份驗證嗎?這將使您的 Bambuddy 實例無需登入即可存取。所有使用者將保留在資料庫中但身份驗證將被停用。',
+ disableAuthentication: '停用身份驗證',
+ // Additional settings
+ configureBambuddy: '設定 Bambuddy',
+ systemDefault: '系統預設',
+ archiveSettings: '歸檔設定',
+ newWindow: '新視窗',
+ embeddedOverlay: '嵌入式疊加層',
+ preferredSlicer: '首選切片軟體',
+ preferredSlicerDescription: '選擇要用於開啟檔案的切片軟體',
+ externalCameras: '外部攝影機',
+ costTracking: '成本追蹤',
+ printsOnly: '僅列印',
+ totalConsumption: '總消耗',
+ dataManagement: '資料管理',
+ storageUsage: '儲存使用情況',
+ storageUsageDescription: '按類別的資料使用情況明細',
+ storageUsageTotal: '總計',
+ storageUsageErrors: '錯誤',
+ storageUsageOtherBreakdown: '其他(包括靜態資源、腳本和設定檔案)',
+ storageUsageSystem: '系統',
+ storageUsageData: '資料',
+ storageUsageUnavailable: '儲存使用資訊不可用',
+ clearNotificationLogsDescription: '刪除 30 天前的通知日誌',
+ resetUiPreferencesDescription: '重設側邊欄順序、主題、檢視模式和佈局偏好。印表機、歸檔和設定不受影響。',
+ enableHomeAssistant: '啟用 Home Assistant',
+ enableMqtt: '啟用 MQTT',
+ useTls: '使用 TLS',
+ enableMetricsEndpoint: '啟用指標端點',
+ availableMetrics: '可用指標',
+ editUser: '編輯使用者',
+ deleteUserTitle: '刪除使用者',
+ groupName: '群組名稱',
+ // Placeholders
+ leaveEmptyForAnonymous: '留空為匿名',
+ leaveEmptyForNoAuth: '留空為無認證',
+ enterNewPassword: '輸入新密碼',
+ confirmNewPassword: '確認新密碼',
+ enterGroupName: '輸入群組名稱',
+ enterDescriptionOptional: '輸入描述(可選)',
+ enterCurrentPassword: '輸入目前密碼',
+ enterNewPasswordMin6: '輸入新密碼(至少 6 個字元)',
+ toast: {
+ keyCopied: '金鑰已複製到剪貼簿',
+ copyFailed: '複製金鑰失敗',
+ keyAddedToBrowser: '金鑰已新增到 API 瀏覽器',
+ clearLogsFailed: '清除日誌失敗',
+ uiPreferencesReset: 'UI 偏好已重設。重新整理中...',
+ authDisabled: '身份驗證已成功停用',
+ authDisableFailed: '停用身份驗證失敗',
+ apiKeyCreated: 'API 金鑰已建立',
+ apiKeyDeleted: 'API 金鑰已刪除',
+ userCreated: '使用者建立成功',
+ userUpdated: '使用者更新成功',
+ userDeleted: '使用者刪除成功',
+ groupCreated: '群組建立成功',
+ groupUpdated: '群組更新成功',
+ groupDeleted: '群組刪除成功',
+ fillRequiredFields: '請填寫所有必填欄位',
+ passwordsDoNotMatch: '密碼不符',
+ passwordTooShort: '密碼至少需要 6 個字元',
+ enterGroupName: '請輸入群組名稱',
+ settingsSaved: '設定已儲存',
+ cameraSettingsSaved: '攝影機設定已儲存',
+ enterCameraUrl: '請輸入攝影機 URL',
+ passwordChanged: '密碼修改成功',
+ connectionFailed: '連線失敗',
+ testFailed: '測試失敗',
+ cameraConnected: '攝影機已連線{{resolution}}',
+ },
+ testConnection: '測試連線',
+ catalog: {
+ spoolCatalog: '耗材目錄',
+ spoolCatalogDescription: '按品牌/類型的空耗材重量。用於新增耗材時的自動重量查詢。',
+ searchCatalog: '搜尋目錄...',
+ addNewEntry: '新增新條目',
+ namePlaceholder: '名稱(例如:Bambu Lab - 塑膠)',
+ weight: '重量',
+ type: '類型',
+ default: '預設',
+ custom: '自訂',
+ noMatch: '沒有條目匹配您的搜尋',
+ empty: '目錄中沒有條目',
+ deleteEntry: '刪除條目',
+ deleteConfirm: '確定要刪除"{{name}}"嗎?',
+ resetCatalog: '重設目錄',
+ resetConfirm: '重設目錄為預設值?這將移除所有自訂條目。',
+ loadFailed: '載入耗材目錄失敗',
+ nameWeightRequired: '名稱和重量為必填項',
+ entryAdded: '條目已新增',
+ addFailed: '新增條目失敗',
+ entryUpdated: '條目已更新',
+ updateFailed: '更新條目失敗',
+ entryDeleted: '條目已刪除',
+ deleteFailed: '刪除條目失敗',
+ resetSuccess: '目錄已重設為預設值',
+ resetFailed: '重設目錄失敗',
+ exported: '已匯出 {{count}} 條',
+ imported: '已匯入 {{added}} 條(跳過 {{skipped}} 條)',
+ importFailed: '匯入失敗:無效的 JSON 格式',
+ exportTooltip: '匯出目錄為 JSON',
+ importTooltip: '從 JSON 匯入目錄',
+ resetTooltip: '重設為預設值',
+ selectedCount: '已選擇 {{count}} 項',
+ deleteSelected: '刪除所選',
+ bulkDeleteConfirm: '確定要刪除 {{count}} 個條目嗎?',
+ bulkDeleted: '已刪除 {{count}} 個條目',
+ bulkDeleteFailed: '刪除條目失敗',
+ },
+ colorCatalog: {
+ title: '顏色目錄',
+ description: '按製造商/材料的耗材顏色。用於新增耗材時的自動顏色查詢。',
+ searchColors: '搜尋顏色...',
+ allManufacturers: '所有製造商',
+ addNewColor: '新增新顏色',
+ manufacturer: '製造商',
+ colorName: '顏色名稱',
+ hex: '十六進位',
+ materialOptional: '材料(可選)',
+ showing: '顯示 {{filtered}} / {{total}} 種顏色',
+ noMatch: '沒有顏色匹配您的搜尋',
+ empty: '目錄中沒有顏色',
+ deleteColor: '刪除顏色',
+ deleteConfirm: '確定要刪除"{{name}}"嗎?',
+ resetCatalog: '重設顏色目錄',
+ resetConfirm: '重設目錄為預設值?這將移除所有自訂顏色。',
+ sync: '同步',
+ starting: '啟動中...',
+ syncTooltip: '從 FilamentColors.xyz 同步(2000+ 種顏色,可能需要一分鐘)',
+ loadFailed: '載入顏色目錄失敗',
+ fieldsRequired: '製造商、顏色名稱和十六進位顏色為必填項',
+ colorAdded: '顏色已新增',
+ addFailed: '新增顏色失敗',
+ colorUpdated: '顏色已更新',
+ updateFailed: '更新顏色失敗',
+ colorDeleted: '顏色已刪除',
+ deleteFailed: '刪除顏色失敗',
+ resetSuccess: '顏色目錄已重設為預設值',
+ resetFailed: '重設目錄失敗',
+ syncUpToDate: '已是最新(檢查了 {{count}} 種顏色)',
+ syncComplete: '新增了 {{added}} 種新顏色({{skipped}} 種已存在)',
+ syncError: '同步錯誤',
+ syncFailed: '從 FilamentColors.xyz 同步失敗',
+ exported: '已匯出 {{count}} 種顏色',
+ imported: '已匯入 {{added}} 種顏色(跳過 {{skipped}} 種)',
+ importFailed: '匯入失敗:無效的 JSON 格式',
+ selectedCount: '已選擇 {{count}} 項',
+ deleteSelected: '刪除所選',
+ bulkDeleteConfirm: '確定要刪除 {{count}} 種顏色嗎?',
+ bulkDeleted: '已刪除 {{count}} 種顏色',
+ bulkDeleteFailed: '刪除顏色失敗',
+ },
+ dateFormat: '日期格式',
+ dateFormatUs: '美式 (MM/DD/YYYY)',
+ dateFormatEu: '歐式 (DD/MM/YYYY)',
+ dateFormatIso: 'ISO (YYYY-MM-DD)',
+ timeFormat: '時間格式',
+ timeFormat12: '12小時制 (3:30 PM)',
+ timeFormat24: '24小時制 (15:30)',
+ defaultPrinter: '預設印表機',
+ defaultPrinterDescription: '為上傳、重印和其他操作預選此印表機。',
+ slicerBambuStudio: 'Bambu Studio',
+ slicerOrcaSlicer: 'OrcaSlicer',
+ sidebarOrderDescription: '拖曳側邊欄項目以重新排序。在此處重設為預設順序。',
+ setDefault: '設為預設',
+ sidebarOrderSetDefaultHint: '設為預設將目前選單順序套用於尚未自訂的使用者。',
+ sidebarDefaultSet: '已設定預設選單順序。',
+ sidebarDefaultCleared: '已清除預設選單順序。',
+ sidebarDefaultFailed: '設定預設選單順序失敗。',
+ reset: '重設',
+ darkMode: '深色模式',
+ lightMode: '淺色模式',
+ active: '(目前)',
+ background: '背景',
+ accent: '強調色',
+ style: '樣式',
+ bgNeutral: '中性',
+ bgWarm: '暖色',
+ bgCool: '冷色',
+ bgOled: 'OLED 純黑',
+ bgSlate: '石板藍',
+ bgForest: '森林綠',
+ accentGreen: '綠色',
+ accentTeal: '青色',
+ accentBlue: '藍色',
+ accentOrange: '橙色',
+ accentPurple: '紫色',
+ accentRed: '紅色',
+ styleClassic: '經典',
+ styleGlow: '發光',
+ styleVibrant: '鮮豔',
+ themeToggleHint: '使用側邊欄中的太陽/月亮圖示在深色和淺色模式之間切換。',
+ autoArchivePrints: '自動歸檔列印',
+ autoArchiveDescription: '列印完成時自動儲存3MF檔案',
+ saveThumbnailsDescription: '從3MF檔案中提取並儲存預覽影像',
+ captureFinishPhotoDescription: '列印完成時從印表機攝影機拍照',
+ ffmpegNotInstalled: '未安裝ffmpeg',
+ ffmpegRequired: '攝影機捕獲需要ffmpeg。透過 brew install ffmpeg(macOS)或 apt install ffmpeg(Linux)安裝。',
+ camera: '攝影機',
+ cameraViewMode: '攝影機檢視模式',
+ cameraOverlayDescription: '攝影機在主螢幕上以可調大小的覆蓋層開啟',
+ cameraWindowDescription: '攝影機在單獨的瀏覽器視窗中開啟',
+ externalCamerasDescription: '設定外部攝影機以替換內建印表機攝影機。支援MJPEG流、RTSP、HTTP快照和USB攝影機(V4L2)。啟用後,外部攝影機將用於即時檢視和完成照片。',
+ cameraPlaceholderUsb: '裝置路徑 (/dev/video0)',
+ cameraPlaceholderUrl: '攝影機URL (rtsp://... 或 http://...)',
+ cameraTypeMjpeg: 'MJPEG 流',
+ cameraTypeRtsp: 'RTSP 流',
+ cameraTypeSnapshot: 'HTTP 快照',
+ cameraTypeUsb: 'USB 攝影機 (V4L2)',
+ cameraRotation: '旋轉',
+ test: '測試',
+ connected: '已連線',
+ disconnected: '未連線',
+ currency: '貨幣',
+ defaultFilamentCost: '預設耗材成本(每公斤)',
+ electricityCost: '每千瓦時電費',
+ energyDisplayMode: '能源顯示模式',
+ energyModePrintDescription: '儀表板顯示列印期間使用的能源總和',
+ energyModeTotalDescription: '儀表板顯示智慧插座的累計能源',
+ fileManager: '檔案管理器',
+ createArchiveEntry: '列印時建立歸檔條目',
+ createArchiveEntryDescription: '從檔案管理器列印時,可選擇建立歸檔條目',
+ lowDiskSpaceWarning: '磁碟空間不足警告',
+ lowDiskSpaceDescription: '當可用磁碟空間低於此閾值時顯示警告',
+ printerFirmware: '印表機韌體',
+ checkFirmwareDescription: '檢查Bambu Lab的印表機韌體更新',
+ bambuddySoftware: 'Bambuddy 軟體',
+ autoCheckDescription: '啟動時自動檢查新版本',
+ checkNow: '立即檢查',
+ updateAvailableVersion: '可用更新:v{{version}}',
+ releaseNotes: '發布說明',
+ updateViaDocker: '透過 Docker Compose 更新:',
+ installUpdate: '安裝更新',
+ latestVersionRunning: '您正在執行最新版本',
+ failedToCheckUpdates: '檢查更新失敗:{{error}}',
+ backupRestore: '備份與恢復',
+ backupRestoreDescription: '匯出/匯入設定並設定GitHub 備份',
+ goToBackup: '前往備份',
+ externalUrl: '外部URL',
+ externalUrlDescription: 'Bambuddy可存取的外部URL。用於通知影像和外部整合。',
+ bambuddyUrl: 'Bambuddy URL',
+ externalUrlHint: '包含協定和連接埠(例如:http://192.168.1.100:8000)',
+ ftpRetry: 'FTP重試',
+ ftpRetryDescription: '當印表機Wi-Fi 不穩定時重試FTP操作。適用於3MF下載、列印上傳、縮時攝影下載和韌體更新。',
+ autoRetryDescription: '自動重試失敗的FTP操作',
+ retryAttempts: '重試次數',
+ retryDelay: '重試延遲',
+ connectionTimeout: '連線超時',
+ time_one: '{{count}} 次',
+ time_other: '{{count}} 次',
+ second_one: '{{count}} 秒',
+ second_other: '{{count}} 秒',
+ nSeconds: '{{count}} 秒',
+ increaseForWeakWifi: '對Wi-Fi 訊號弱的印表機增加此值',
+ homeAssistant: 'Home Assistant',
+ homeAssistantFullDescription: '連線到Home Assistant,透過HA REST API控制智慧插座。支援switch、light、input_boolean和script實體。',
+ homeAssistantUrl: 'Home Assistant URL',
+ longLivedAccessToken: '長期存取權杖',
+ haTokenHint: '在HA中建立權杖:個人資料 → 長期存取權杖 → 建立權杖',
+ connectionSuccessful: '連線成功',
+ connectionFailed: '連線失敗',
+ haConnectionSuccess: '已成功連線到Home Assistant。',
+ haConnectionFailed: '連線Home Assistant失敗。',
+ mqttPublishing: 'MQTT發布',
+ mqttDescription: '將BamBuddy事件發布到外部MQTT代理,用於與Node-RED、Home Assistant和其他自動化系統整合。',
+ mqttEnableDescription: '向外部MQTT代理發布事件',
+ brokerHostname: '代理主機名稱',
+ port: '連接埠',
+ usernameOptional: '使用者名稱(可選)',
+ passwordOptional: '密碼(可選)',
+ topicPrefix: '主題前綴',
+ topicPrefixHint: '主題格式:{{prefix}}/printers//status 等',
+ prometheusMetrics: 'Prometheus 指標',
+ prometheusEndpointDescription: '在 /api/v1/metrics 公開印表機指標,用於Prometheus/Grafana監控。',
+ bearerTokenOptional: 'Bearer權杖(可選)',
+ bearerTokenHint: '設定後,請求必須包含 Authorization: Bearer ',
+ metricsConnectionStatus: '連線狀態',
+ metricsPrinterState: '印表機狀態(空閒/列印中等)',
+ metricsPrintProgress: '列印進度 0-100%',
+ metricsBedTemp: '熱床溫度',
+ metricsNozzleTemp: '噴嘴溫度',
+ metricsPrintsTotal: '按結果分類的總列印數',
+ metricsMore: '...以及更多(層數、風扇、佇列、耗材用量)',
+ smartPlugsDescription: '連線智慧插座(Tasmota或Home Assistant)以自動化電源控制並追蹤印表機的能源使用情況。',
+ allOn: '全部開啟',
+ allOff: '全部關閉',
+ addSmartPlug: '新增智慧插座',
+ energySummary: '能源概要',
+ currentPower: '目前功率',
+ plugsOnline: '{{reachable}}/{{total}} 個插座線上',
+ today: '今天',
+ yesterday: '昨天',
+ total: '總計',
+ enablePlugsForSummary: '啟用插座以檢視能源概要',
+ addNotificationProvider: '新增',
+ systemBadge: '(系統)',
+ creating: '建立中...',
+ changing: '修改中...',
+ deleteUserAndItems: '刪除使用者及其所有項目',
+ deleteUserKeepItems: '刪除使用者,保留項目(將變為無主項目)',
+ ok: '確定',
+
+ // 2FA settings
+ twoFa: {
+ totpTitle: '身份驗證器 App (TOTP)',
+ totpDesc: '使用 Google Authenticator、Aegis 或 Authy 等 App。',
+ emailOtpTitle: '郵件 OTP',
+ emailOtpDesc: '登入時向 {{email}} 傳送一次性驗證碼。',
+ emailOtpNoEmail: '請先為帳戶新增信箱地址以啟用此方式。',
+ addEmailFirst: '您的帳戶沒有信箱地址,請聯絡管理員新增。',
+ setupTotp: '設定身份驗證器 App',
+ setupAuthApp: '設定身份驗證器 App',
+ setupInstructions: '使用身份驗證器 App 掃描QR Code,然後輸入驗證碼確認。',
+ manualEntry: '無法掃描?請手動輸入此金鑰:',
+ scannedContinue: '已掃描 — 繼續',
+ enterCodeToConfirm: '請輸入身份驗證器 App 中的6位驗證碼以確認設定。',
+ activate: '啟用',
+ disableTotp: '停用身份驗證器',
+ disableConfirmHint: '請輸入有效的 TOTP 碼或備用碼來停用身份驗證器。',
+ totpDisabled: '身份驗證器 App 已停用。',
+ emailOtpEnabled: '郵件 OTP 已啟用。',
+ emailOtpDisabled: '郵件 OTP 已停用。',
+ smtpRequired: '請先設定並測試SMTP設定。',
+ invalidCode: '無效驗證碼,請重試。',
+ enableEmailOtp: '啟用郵件 OTP',
+ disableEmailOtp: '停用郵件 OTP',
+ emailSetupEnterCode: '驗證碼已傳送至您的信箱地址。請在下方輸入以確認您擁有此信箱。',
+ verifyAndEnable: '驗證並啟用',
+ emailDisablePasswordHint: '請輸入您的帳戶密碼以確認停用郵件 OTP。',
+ passwordPlaceholder: '輸入您的密碼',
+ backupCodesTitle: '儲存備用碼',
+ backupCodesWarning: '請將這些碼儲存在安全的地方。每個碼只能使用一次,且不會再次顯示。',
+ backupCodesRemaining: '剩餘 {{count}} 個備用碼',
+ savedCodes: '已儲存',
+ regenBackup: '重新產生備用碼',
+ regenBackupHint: '輸入目前 TOTP 碼以產生 10 個新備用碼,所有現有備用碼將失效。',
+ newBackupCodes: '新備用碼',
+ linkedAccounts: '已連結的 SSO 帳戶',
+ linkedAccountsDesc: '以下外部身份提供者已與您的帳戶連結。',
+ oidcUnlinked: '帳戶已解除連結。',
+ },
+
+ // OIDC provider settings
+ oidc: {
+ title: 'SSO / OIDC 提供者',
+ desc: '設定 OpenID Connect 提供者以實現單點登入。',
+ addProvider: '新增提供者',
+ newProvider: '新提供者',
+ empty: '尚未設定 OIDC 提供者。',
+ created: '提供者已建立。',
+ updated: '提供者已更新。',
+ deleted: '提供者已刪除。',
+ deleteTitle: '刪除提供者',
+ deleteMessage: '刪除"{{name}}"?所有連結帳戶將斷開連線。',
+ form: {
+ name: '顯示名稱',
+ issuerUrl: '頒發者 URL',
+ clientId: '客戶端 ID',
+ clientSecret: '客戶端金鑰',
+ scopes: '作用域',
+ iconUrl: '圖示 URL(可選)',
+ enabled: '已啟用',
+ autoCreate: '自動建立使用者',
+ autoCreateDesc: '首次登入時自動建立本機帳戶。',
+ autoLink: '自動連結已有帳戶',
+ autoLinkDesc: '首次登入時透過信箱匹配現有本機帳戶並自動連結。',
+ secretHint: '留空以保留目前',
+ secretPlaceholder: '新金鑰',
+ },
+ },
+
+ },
+
+ // Notifications (for push notifications)
+ notification: {
+ printStarted: {
+ title: '列印已開始',
+ body: '{{printer}}:{{filename}} 已開始列印',
+ },
+ printCompleted: {
+ title: '列印已完成',
+ body: '{{printer}}:{{filename}} 已成功完成',
+ },
+ printFailed: {
+ title: '列印失敗',
+ body: '{{printer}}:{{filename}} 列印失敗',
+ },
+ printStopped: {
+ title: '列印已停止',
+ body: '{{printer}}:{{filename}} 已停止',
+ },
+ printProgress: {
+ title: '列印進度',
+ body: '{{printer}}:{{filename}} 已完成 {{percent}}%',
+ },
+ printerOffline: {
+ title: '印表機離線',
+ body: '{{printer}} 已離線',
+ },
+ printerError: {
+ title: '印表機錯誤',
+ body: '{{printer}}:{{error}}',
+ },
+ filamentLow: {
+ title: '耗材不足',
+ body: '{{printer}}:耗材即將用完',
+ },
+ maintenanceDue: {
+ title: '維護到期',
+ body: '{{printer}}:{{items}} 需要關注',
+ },
+ },
+
+ // Errors
+ errors: {
+ generic: '出了點問題',
+ networkError: '網路錯誤。請檢查您的連線。',
+ notFound: '未找到',
+ unauthorized: '未授權',
+ serverError: '伺服器錯誤',
+ validationError: '請檢查您的輸入',
+ printerConnectionFailed: '連線印表機失敗',
+ saveFailed: '儲存更改失敗',
+ deleteFailed: '刪除失敗',
+ loadFailed: '載入資料失敗',
+ },
+
+ // HMS Errors modal
+ hmsErrors: {
+ title: '錯誤 - {{name}}',
+ noErrors: '無錯誤',
+ viewOnWiki: '在拓竹 Wiki 上檢視',
+ clearInstructions: '在印表機上清除錯誤以在此處消除它們。',
+ clearErrors: '清除錯誤',
+ clearSuccess: 'HMS 錯誤已清除',
+ clearFailed: '清除 HMS 錯誤失敗',
+ },
+
+ // MQTT Debug modal
+ mqttDebug: {
+ title: 'MQTT 偵錯日誌',
+ searchPlaceholder: '搜尋主題或負載...',
+ noMessages: '尚未紀錄訊息',
+ startLoggingHint: '點選"開始紀錄"以開始捕獲 MQTT 訊息',
+ noMessagesMatch: '沒有訊息匹配您的篩選條件',
+ adjustFilterHint: '嘗試調整您的搜尋或篩選條件',
+ incoming: '傳入',
+ outgoing: '傳出',
+ loggingStopped: '紀錄已停止',
+ loggingActive: '紀錄中 - 訊息將自動重新整理',
+ startLogging: '開始紀錄',
+ stopLogging: '停止紀錄',
+ clearLog: '清除日誌',
+ topic: '主題',
+ timestamp: '時間戳',
+ direction: '方向',
+ all: '全部',
+ },
+
+ // Printer File Manager modal (printer internal storage)
+ printerFiles: {
+ title: '檔案管理器',
+ storageUsed: '已用:',
+ storageFree: '剩餘:',
+ filterPlaceholder: '篩選檔案...',
+ deleteButton: '刪除',
+ deleteFiles: '刪除 {{count}} 個檔案',
+ deleteFileConfirm: '刪除"{{name}}"?此操作無法復原。',
+ deleteFilesConfirm: '刪除 {{count}} 個選中的檔案?此操作無法復原。',
+ noFiles: '印表機上沒有檔案',
+ loadingFiles: '載入檔案中...',
+ failedToLoad: '載入檔案失敗',
+ toast: {
+ filesDeleted: '已刪除 {{count}} 個檔案',
+ deleteFailed: '刪除失敗:{{error}}',
+ },
+ },
+
+ // Confirmations
+ confirm: {
+ delete: '確定要刪除嗎?',
+ unsavedChanges: '您有未儲存的更改。確定要離開嗎?',
+ clearQueue: '確定要清空佇列嗎?',
+ },
+
+ // Login page
+ login: {
+ title: 'Bambuddy 登入',
+ subtitle: '登入您的帳戶',
+ username: '使用者名稱',
+ usernamePlaceholder: '輸入您的使用者名稱',
+ usernameOrEmail: '使用者名稱或信箱',
+ usernameOrEmailPlaceholder: '使用者名稱或 @ 信箱',
+ password: '密碼',
+ passwordPlaceholder: '輸入您的密碼',
+ signIn: '登入',
+ signingIn: '登入中...',
+ forgotPassword: '忘記密碼?',
+ loginSuccess: '登入成功',
+ loginFailed: '登入失敗',
+ enterCredentials: '請輸入使用者名稱和密碼',
+ enterEmail: '請輸入您的電子郵件地址',
+ oidcLoginFailed: 'OIDC 登入失敗',
+ oidcErrors: {
+ providerError: '身份提供者返回了一個錯誤',
+ missingParameters: 'OIDC 回呼缺少必要引數',
+ invalidState: 'OIDC 狀態無效或已被使用',
+ stateExpired: 'OIDC 登入會話已過期,請重試',
+ providerNotFound: '未找到 OIDC 提供者',
+ discoveryFailed: '無法獲取 OIDC 探索文件',
+ invalidDiscovery: 'OIDC 探索文件無效',
+ networkError: 'OIDC 權杖交換時出現網路錯誤',
+ badResponse: 'OIDC 權杖交換時收到意外回應',
+ noIdToken: 'OIDC 提供者未返回 ID 權杖',
+ validationFailed: 'OIDC 權杖驗證失敗',
+ nonceMismatch: 'OIDC nonce 不符,可能存在重放攻擊',
+ missingSubClaim: 'OIDC 權杖缺少 sub 宣告',
+ noLinkedAccount: '沒有與此 OIDC 身份連結的本機帳戶',
+ accountInactive: '您的帳戶已被停用',
+ userResolutionFailed: '無法解析您的帳戶',
+ internalError: 'OIDC 登入過程中發生內部錯誤',
+ tokenExchangeFailed: 'OIDC 權杖交換失敗',
+ },
+ forgotPasswordTitle: '忘記密碼',
+ forgotPasswordMessage: '如果您忘記了密碼,請聯絡系統管理員進行重設。',
+ forgotPasswordEmailMessage: '輸入您的信箱地址,我們將向您傳送新密碼。',
+ emailAddress: '信箱地址',
+ emailPlaceholder: 'your.email@example.com',
+ cancel: '取消',
+ sending: '傳送中...',
+ sendResetEmail: '傳送重設郵件',
+ howToReset: '如何重設密碼:',
+ resetStep1: '聯絡您的 Bambuddy 管理員',
+ resetStep2: '請他們在使用者管理中重設您的密碼',
+ resetStep3: '他們可以為您設定一個臨時密碼',
+ resetStep4: '使用新密碼登入並在設定中修改密碼',
+ gotIt: '知道了',
+ resetPassword: {
+ title: '設定新密碼',
+ subtitle: '請在下方輸入並確認您的新密碼。',
+ newPassword: '新密碼',
+ newPasswordPlaceholder: '至少 8 個字元',
+ confirmPassword: '確認密碼',
+ confirmPasswordPlaceholder: '重複輸入新密碼',
+ saving: '儲存中…',
+ submit: '設定新密碼',
+ backToLogin: '回到登入',
+ passwordsDoNotMatch: '密碼不符',
+ passwordTooShort: '密碼至少需要 8 個字元',
+ resetFailed: '密碼重設失敗。連結可能已過期。',
+ },
+ twoFA: {
+ title: '兩步驗證',
+ subtitle: '您的帳戶已啟用兩步驗證。請在下方輸入驗證碼。',
+ methodAuthenticator: '身份驗證器 App',
+ methodEmail: '信箱驗證碼',
+ methodBackup: '備用恢復碼',
+ instructionsTotp: '請開啟您的身份驗證器 App,輸入 Bambuddy 的 6 位驗證碼。',
+ instructionsEmail: '6 位驗證碼已傳送至您的信箱,有效期為 10 分鐘。',
+ instructionsEmailNotSent: '點選下方按鈕,透過郵件獲取驗證碼。',
+ instructionsBackup: '請輸入您的一個 8 位備用恢復碼。每個恢復碼只能使用一次。',
+ sendCodeButton: '傳送信箱驗證碼',
+ sendingCode: '傳送中...',
+ resendCode: '重新傳送驗證碼',
+ codeLabel: '驗證碼',
+ backupCodeLabel: '備用恢復碼',
+ codePlaceholder: '000000',
+ backupCodePlaceholder: 'XXXXXXXX',
+ verifyButton: '驗證',
+ verifyingButton: '驗證中...',
+ backToLogin: '← 回到登入頁面',
+ orContinueWith: '或透過以下方式登入',
+ signInWith: '使用 {{provider}} 登入',
+ enterCode: '請輸入驗證碼',
+ sendCodeFailed: '驗證碼傳送失敗',
+ invalidCode: '無效驗證碼,請重試。',
+ },
+
+ },
+
+ // Setup page
+ setup: {
+ title: 'Bambuddy 設定',
+ subtitle: '為您的 Bambuddy 實例設定身份驗證',
+ enableAuth: '啟用身份驗證',
+ adminAccount: '管理員帳戶',
+ adminAccountDesc: '如果管理員使用者已存在,將使用現有管理員帳戶啟用身份驗證。如需使用現有管理員,請將下方欄位留空,或輸入新憑據建立新管理員使用者。',
+ adminUsername: '管理員使用者名稱',
+ adminPassword: '管理員密碼',
+ optionalIfAdminExists: '(如管理員使用者已存在則為可選)',
+ adminUsernamePlaceholder: '輸入管理員使用者名稱(可選)',
+ adminPasswordPlaceholder: '輸入管理員密碼(可選)',
+ confirmPassword: '確認密碼',
+ confirmPasswordPlaceholder: '確認管理員密碼',
+ settingUp: '設定中...',
+ completeSetup: '完成設定',
+ toast: {
+ authEnabledAdminCreated: '身份驗證已啟用並建立了管理員使用者',
+ authEnabledExistingAdmins: '使用現有管理員使用者啟用了身份驗證',
+ setupCompleted: '設定完成',
+ enterBothCredentials: '請輸入管理員使用者名稱和密碼,或將兩者留空以使用現有管理員使用者',
+ passwordsDoNotMatch: '密碼不符',
+ passwordTooShort: '密碼至少需要 6 個字元',
+ },
+ },
+
+ // Password change
+ changePassword: {
+ title: '修改密碼',
+ currentPassword: '目前密碼',
+ currentPasswordPlaceholder: '輸入目前密碼',
+ newPassword: '新密碼',
+ newPasswordPlaceholder: '輸入新密碼(至少 6 個字元)',
+ confirmPassword: '確認新密碼',
+ confirmPasswordPlaceholder: '確認新密碼',
+ passwordsDoNotMatch: '密碼不符',
+ passwordTooShort: '密碼至少需要 6 個字元',
+ changing: '修改中...',
+ success: '密碼修改成功',
+ failed: '密碼修改失敗',
+ },
+
+ // Plate detection alert
+ plateAlert: {
+ title: '列印已暫停!',
+ message: '在列印板上偵測到物體。列印已自動暫停。請清理列印板並繼續列印。',
+ understand: '我知道了',
+ },
+
+ // Camera page
+ camera: {
+ title: '攝影機檢視',
+ invalidPrinterId: '無效的印表機 ID',
+ live: '即時',
+ snapshot: '快照',
+ restartStream: '重新啟動流',
+ refreshSnapshot: '重新整理快照',
+ fullscreen: '全螢幕',
+ exitFullscreen: '離開全螢幕',
+ connectingToCamera: '連線攝影機中...',
+ capturingSnapshot: '拍攝快照中...',
+ connectionLost: '連線已斷開',
+ connectionFailed: '攝影機連線失敗',
+ reconnecting: '{{countdown}} 秒後重新連線...(第 {{attempt}}/{{max}} 次嘗試)',
+ reconnectNow: '立即重新連線',
+ cameraUnavailable: '攝影機不可用',
+ cameraUnavailableDesc: '請確保印表機已通電並已連線。',
+ noCamera: '無可用攝影機',
+ retry: '重試',
+ cameraStream: '攝影機流',
+ zoomOut: '縮小',
+ zoomIn: '放大',
+ resetZoom: '重設縮放',
+ recording: '錄製中',
+ startRecording: '開始錄製',
+ stopRecording: '停止錄製',
+ chamberLight: '切換腔室燈',
+ },
+
+ // Groups management
+ groups: {
+ title: '群組管理',
+ subtitle: '管理存取控制的權限群組',
+ backToSettings: '返回設定',
+ createGroup: '建立群組',
+ noPermission: '您沒有存取此頁面的權限。',
+ system: '系統',
+ noDescription: '無描述',
+ usersCount: '{{count}} 個使用者',
+ permissionsCount: '{{count}} 個權限',
+ edit: '編輯',
+ delete: '刪除',
+ toast: {
+ created: '群組建立成功',
+ updated: '群組更新成功',
+ deleted: '群組刪除成功',
+ enterGroupName: '請輸入群組名稱',
+ },
+ modal: {
+ editGroup: '編輯群組',
+ createGroup: '建立群組',
+ cancel: '取消',
+ saving: '儲存中...',
+ creating: '建立中...',
+ saveChanges: '儲存更改',
+ },
+ form: {
+ groupName: '群組名稱',
+ groupNamePlaceholder: '輸入群組名稱',
+ systemGroupWarning: '系統群組名稱不可更改',
+ description: '描述',
+ descriptionPlaceholder: '輸入描述(可選)',
+ permissions: '權限(已選 {{count}} 個)',
+ },
+ deleteModal: {
+ title: '刪除群組',
+ message: '確定要刪除此群組嗎?此群組中的使用者將失去這些權限。',
+ confirm: '刪除群組',
+ },
+ editor: {
+ title: '編輯群組',
+ createTitle: '建立群組',
+ search: '搜尋權限...',
+ selectAll: '全選',
+ clearAll: '清除全部',
+ permissionsSelected: '已選 {{count}} 個',
+ noResults: '沒有權限匹配您的搜尋',
+ },
+ },
+
+ // Users management
+ users: {
+ title: '使用者管理',
+ subtitle: '管理使用者及其對 Bambuddy 實例的存取',
+ backToSettings: '返回設定',
+ createUser: '建立使用者',
+ noPermission: '您沒有存取此頁面的權限。',
+ admin: '管理員',
+ noGroups: '無群組',
+ active: '活躍',
+ inactive: '非活躍',
+ edit: '編輯',
+ delete: '刪除',
+ system: '系統',
+ noGroupsAvailable: '無可用群組',
+ table: {
+ username: '使用者名稱',
+ groups: '群組',
+ status: '狀態',
+ actions: '操作',
+ },
+ toast: {
+ created: '使用者建立成功',
+ updated: '使用者更新成功',
+ deleted: '使用者刪除成功',
+ fillRequired: '請填寫所有必填欄位',
+ passwordsDoNotMatch: '密碼不符',
+ passwordTooShort: '密碼至少需要 6 個字元',
+ },
+ modal: {
+ createUser: '建立使用者',
+ editUser: '編輯使用者',
+ cancel: '取消',
+ creating: '建立中...',
+ saving: '儲存中...',
+ saveChanges: '儲存更改',
+ advancedAuthSubtitle: '使用進階認證',
+ },
+ form: {
+ username: '使用者名稱',
+ usernamePlaceholder: '輸入使用者名稱',
+ email: '信箱',
+ emailPlaceholder: 'user@example.com',
+ password: '密碼',
+ passwordPlaceholder: '輸入密碼',
+ confirmPassword: '確認密碼',
+ confirmPasswordPlaceholder: '確認密碼',
+ newPasswordPlaceholder: '輸入新密碼',
+ confirmNewPasswordPlaceholder: '確認新密碼',
+ leaveBlankToKeep: '留空以保持目前值',
+ groups: '群組',
+ optional: '可選',
+ autoGeneratedPassword: '將自動產生安全密碼並透過郵件傳送給使用者。',
+ passwordManagedByAdvancedAuth: '密碼由進階認證管理。使用"重設密碼"透過郵件向使用者傳送新密碼。',
+ resetPassword: '重設密碼',
+ resettingPassword: '重設密碼中...',
+ },
+ deleteModal: {
+ title: '刪除使用者',
+ message: '確定要刪除此使用者嗎?此操作無法復原。',
+ confirm: '刪除使用者',
+ },
+ },
+
+ // Stream overlay
+ streamOverlay: {
+ title: '流疊加層',
+ invalidPrinterId: '無效的印表機 ID',
+ cameraStream: '攝影機流',
+ progress: '進度',
+ eta: '預計完成時間',
+ printerIdle: '印表機空閒',
+ printerOffline: '印表機離線',
+ status: {
+ printing: '列印中',
+ paused: '已暫停',
+ finished: '已完成',
+ failed: '失敗',
+ idle: '空閒',
+ unknown: '未知',
+ },
+ },
+
+ // Profiles
+ profiles: {
+ title: '設定檔案',
+ subtitle: '管理您的切片預設和壓力推進校準',
+ tabs: {
+ cloud: '雲端設定檔案',
+ local: '本機設定檔案',
+ kprofiles: 'K 值設定',
+ },
+ localProfiles: {
+ title: '本機設定檔案',
+ subtitle: '從 OrcaSlicer 匯入和管理切片預設',
+ import: '匯入設定檔案',
+ importDesc: '將 .bbscfg、.bbsflmt、.orca_filament、.zip 或 .json 檔案拖放到此處',
+ importing: '匯入中...',
+ search: '搜尋本機預設...',
+ noPresets: '尚無本機預設',
+ badge: '本機',
+ edit: '編輯',
+ delete: '刪除',
+ cancel: '取消',
+ deleteConfirmTitle: '刪除預設',
+ deleteConfirm: '確定要刪除此預設嗎?此操作無法復原。',
+ source: '來源',
+ inheritsFrom: '繼承自',
+ filamentType: '類型',
+ vendor: '廠商',
+ compatiblePrinters: '相容印表機',
+ nozzleTemp: '噴嘴溫度',
+ cost: '成本',
+ density: '密度',
+ pressureAdvance: '壓力推進',
+ filament: '耗材',
+ process: '工藝',
+ printer: '印表機',
+ toast: {
+ importSuccess: '已匯入 {{count}} 個預設',
+ importSkipped: '跳過 {{count}} 個預設(重複)',
+ importError: '匯入時出現 {{count}} 個錯誤',
+ deleted: '預設已刪除',
+ updated: '預設已更新',
+ },
+ },
+ connectedAs: '已連線為',
+ logout: '登出',
+ noLogoutPermission: '您沒有登出的權限',
+ failedToLoad: '載入設定檔案失敗',
+ retry: '重試',
+ time: {
+ justNow: '剛剛',
+ minsAgo: '{{count}} 分鐘前',
+ hoursAgo: '{{count}} 小時前',
+ daysAgo: '{{count}} 天前',
+ },
+ toast: {
+ loggedOut: '已登出',
+ },
+ login: {
+ title: '連線到拓竹雲',
+ subtitle: '跨裝置同步您的切片預設',
+ email: '信箱',
+ password: '密碼',
+ region: '地區',
+ regionGlobal: '全球',
+ regionChina: '中國',
+ verificationCode: '驗證碼',
+ totpCode: '驗證器驗證碼',
+ checkEmail: '檢查您的信箱 ({{email}}) 獲取 6 位驗證碼',
+ enterTotpHint: '輸入驗證器 App 中的 6 位驗證碼',
+ accessToken: '存取權杖',
+ accessTokenHint: '貼上您的拓竹存取權杖(來自 Bambu Studio)',
+ back: '返回',
+ loginButton: '登入',
+ verifyButton: '驗證',
+ setTokenButton: '設定權杖',
+ useToken: '改用存取權杖',
+ useEmail: '改用信箱登入',
+ toast: {
+ loggedIn: '登入成功',
+ codeSent: '驗證碼已傳送到您的信箱',
+ enterTotp: '輸入驗證器 App 中的程式碼',
+ tokenSet: '權杖設定成功',
+ },
+ },
+ presets: {
+ myPreset: '我的預設(可編輯)',
+ duplicate: '複製',
+ editable: '可編輯',
+ failedToLoadDetails: '載入預設詳情失敗',
+ deleteConfirm: '刪除此預設?',
+ deleteWarning: '這將從拓竹雲中永久刪除"{{name}}"。此操作無法復原。',
+ noDuplicatePermission: '您沒有複製預設的權限',
+ noEditPermission: '您沒有編輯預設的權限',
+ noDeletePermission: '您沒有刪除預設的權限',
+ types: {
+ filament: '耗材預設',
+ printer: '印表機預設',
+ process: '工藝預設',
+ },
+ toast: {
+ deleted: '預設已刪除',
+ created: '預設已建立',
+ updated: '預設已更新',
+ duplicated: '預設已複製',
+ fieldAdded: '欄位"{{key}}"已新增',
+ exported: '預設已匯出',
+ },
+ baseLabel: '基礎:{{name}}',
+ currentLabel: '目前:{{name}}',
+ newPreset: '新增預設',
+ editPreset: '編輯預設',
+ duplicatePreset: '複製預設',
+ createNewPreset: '建立新預設',
+ customizeSettings: '自訂新預設的設定',
+ compareWithBase: '與基礎預設比較',
+ compare: '比較',
+ // CreatePresetModal - Basic Info
+ basePreset: '基礎預設',
+ selectBasePreset: '選擇基礎預設...',
+ presetName: '預設名稱',
+ myCustomPreset: '我的自訂預設',
+ inheritsFrom: '繼承自',
+ dropJsonToImport: '拖放 JSON 以匯入',
+ // CreatePresetModal - Tabs
+ tabs: {
+ common: '常用',
+ allFields: '所有欄位',
+ },
+ // CreatePresetModal - All Fields Tab
+ availableFields: '可用欄位',
+ searchFieldsPlaceholder: '搜尋欄位...',
+ noMatchingFields: '沒有匹配的欄位',
+ allFieldsAdded: '所有欄位已新增',
+ addCustomField: '新增自訂欄位',
+ yourOverrides: '您的覆蓋值',
+ noOverridesYet: '尚無覆蓋值',
+ clickFieldsToAdd: '點選左側的欄位進行新增',
+ saveAsTemplate: '儲存為範本',
+ jsonTip: '提示:將 .json 檔案拖放到此對話方塊的任意位置以匯入設定',
+ },
+ cloudView: {
+ searchPlaceholder: '搜尋預設...',
+ templates: '範本',
+ refresh: '重新整理',
+ newPreset: '新增預設',
+ clearFilters: '清除篩選',
+ // Compare mode
+ compareMode: '比較模式',
+ selectAnotherPreset: '選擇另一個 {{type}} 預設',
+ clickTwoPresets: '點選兩個相同類型的預設進行比較',
+ selectFirst: '1. 選擇第一個',
+ selectSecond: '2. 選擇第二個',
+ compareNow: '立即比較',
+ // Status row
+ lastSynced: '上次同步:',
+ showingCount: '顯示 {{showing}} / {{total}} 個預設',
+ noPresetsFound: '未找到預設',
+ // Column headers
+ columns: {
+ filament: '耗材',
+ process: '工藝',
+ printer: '印表機',
+ },
+ noFilamentPresets: '無耗材預設',
+ noProcessPresets: '無工藝預設',
+ noPrinterPresets: '無印表機預設',
+ // Filters
+ filters: {
+ type: '類型',
+ owner: '所有者',
+ printer: '印表機',
+ nozzle: '噴嘴',
+ filament: '耗材',
+ layer: '層',
+ all: '全部',
+ myPresets: '我的預設',
+ builtIn: '內建',
+ process: '工藝',
+ },
+ // Permissions
+ noTemplatesPermission: '您沒有管理範本的權限',
+ noRefreshPermission: '您沒有重新整理設定檔案的權限',
+ noCreatePermission: '您沒有建立預設的權限',
+ },
+ templates: {
+ title: '快速範本',
+ noTemplates: '尚無範本',
+ createFirst: '從預設編輯器建立範本',
+ typeFilter: '類型:',
+ deleteTitle: '刪除範本',
+ deleteWarning: '此操作無法復原',
+ deleteConfirm: '確定要刪除"{{name}}"嗎?',
+ namePlaceholder: '範本名稱',
+ descriptionPlaceholder: '描述',
+ settingsJson: '設定 (JSON)',
+ fieldsCount: '{{count}} 個欄位',
+ shownInModals: '在對話方塊中顯示',
+ hiddenInModals: '在對話方塊中隱藏',
+ apply: '套用',
+ toast: {
+ deleted: '範本已刪除',
+ updated: '範本已更新',
+ created: '範本已建立',
+ applied: '範本已套用',
+ },
+ },
+ },
+
+ // Support/Debug
+ support: {
+ debugLoggingActive: '偵錯日誌紀錄已啟用',
+ manageLogs: '管理',
+ collectItem7: '印表機連線和韌體版本',
+ collectItem8: '整合狀態(Spoolman、MQTT、HA)',
+ collectItem9: '網路介面(僅子網)',
+ collectItem10: 'Python 套件版本',
+ collectItem11: '資料庫健康檢查',
+ collectItem12: 'Docker 環境詳情',
+ },
+
+ // File manager
+ fileManager: {
+ title: '檔案管理器',
+ subtitle: '組織和管理您的列印檔案',
+ uploadFiles: '上傳檔案',
+ newFolder: '新增資料夾',
+ folderName: '資料夾名稱',
+ folderNamePlaceholder: '例如:功能零件',
+ renameFile: '重新命名檔案',
+ renameFolder: '重新命名資料夾',
+ moveFiles: '移動 {{count}} 個檔案',
+ rootNoFolder: '根目錄(無資料夾)',
+ current: '目前',
+ linkFolder: '連結資料夾',
+ linkFolderDescription: '將"{{name}}"連結到專案或歸檔以便快速存取。',
+ project: '專案',
+ archive: '歸檔',
+ noProjectsFound: '未找到專案',
+ noArchivesFound: '未找到歸檔',
+ unlink: '取消連結',
+ link: '連結',
+ dragDropFiles: '將檔案拖放到此處',
+ dropFilesHere: '將檔案放在此處',
+ orClickToBrowse: '或點選瀏覽',
+ allFileTypesSupported: '支援所有檔案類型。ZIP 檔案將被解壓。',
+ zipFilesDetected: '偵測到 ZIP 檔案',
+ zipExtractOptions: 'ZIP 檔案將被解壓。選擇如何處理資料夾結構:',
+ preserveZipStructure: '保留 ZIP 中的資料夾結構',
+ createFolderFromZip: '從 ZIP 檔名建立資料夾',
+ stlThumbnailGeneration: 'STL 縮圖產生',
+ zipMayContainStl: 'ZIP 檔案可能包含 STL 檔案。可以在解壓時產生縮圖。',
+ thumbnailsCanBeGenerated: '可以為 STL 檔案產生縮圖。大型模型可能需要更長時間處理。',
+ generateThumbnailsForStl: '為 STL 檔案產生縮圖',
+ threemfDetected: '偵測到 3MF 檔案',
+ threemfExtractionInfo: '將自動從 3MF 檔案中提取印表機型號、材料、顏色和列印設定。',
+ willBeExtracted: '將被解壓',
+ filesExtracted: '已解壓 {{count}} 個檔案',
+ uploadComplete: '上傳完成:{{succeeded}} 個成功',
+ uploadFailed: '上傳失敗',
+ zipFilesFailed: '{{count}} 個檔案失敗',
+ uploading: '上傳中...',
+ changeLink: '更改連結...',
+ linkTo: '連結到...',
+ linkToProjectOrArchive: '連結到專案或歸檔',
+ addToQueue: '新增到佇列',
+ schedulePrint: '排程',
+ generateThumbnail: '產生縮圖',
+ generateThumbnails: '產生縮圖',
+ generateThumbnailsForMissing: '為缺少縮圖的 STL 檔案產生縮圖',
+ gridView: '網格檢視',
+ listView: '列表檢視',
+ lowDiskSpaceWarning: '磁碟空間不足警告',
+ lowDiskSpaceDetails: '僅剩 {{free}}(總共 {{total}})。閾值設定為 {{threshold}} GB。',
+ files: '檔案',
+ folders: '資料夾',
+ size: '大小',
+ free: '剩餘',
+ allFiles: '所有檔案',
+ wrap: '換行',
+ enableTextWrapping: '啟用文字換行',
+ disableTextWrapping: '停用文字換行',
+ dragToResizeTooltip: '拖曳調整大小,雙擊重設',
+ searchFiles: '搜尋檔案...',
+ allTypes: '所有類型',
+ prints: '列印',
+ ascending: '升序',
+ descending: '降序',
+ resultsCount: '{{showing}} / {{total}} 個檔案',
+ selectAll: '全選',
+ deselectAll: '取消全選',
+ selected: '已選擇 {{count}} 個',
+ adding: '新增中...',
+ loadingFiles: '載入檔案中...',
+ folderIsEmpty: '資料夾為空',
+ noFilesYet: '尚無檔案',
+ folderEmptyDescription: '上傳檔案或將檔案移入此資料夾以開始使用。',
+ noFilesDescription: '上傳檔案以開始組織您的列印相關檔案。',
+ noMatchingFiles: '沒有匹配的檔案',
+ noMatchingFilesDescription: '沒有檔案匹配您目前的搜尋或篩選條件。',
+ clearFilters: '清除篩選',
+ printedCount: '已列印 {{count}} 次',
+ uploadedBy: '上傳者',
+ deleteFolder: '刪除資料夾',
+ deleteFile: '刪除檔案',
+ deleteFilesCount: '刪除 {{count}} 個檔案',
+ deleteFolderConfirm: '確定要刪除此資料夾嗎?其中的所有檔案也將被刪除。',
+ deleteFileConfirm: '確定要刪除此檔案嗎?',
+ deleteFilesConfirm: '確定要刪除 {{count}} 個選中的檔案嗎?此操作無法復原。',
+ deleting: '刪除中...',
+ noPermissionRenameFolder: '您沒有重新命名資料夾的權限',
+ noPermissionLinkFolder: '您沒有連結資料夾的權限',
+ noPermissionDeleteFolder: '您沒有刪除資料夾的權限',
+ noPermissionPrint: '您沒有列印的權限',
+ noPermissionAddToQueue: '您沒有新增到佇列的權限',
+ noPermissionDownload: '您沒有下載檔案的權限',
+ noPermissionRenameFile: '您沒有重新命名此檔案的權限',
+ noPermissionGenerateThumbnail: '您沒有產生縮圖的權限',
+ noPermissionDeleteFile: '您沒有刪除此檔案的權限',
+ noPermissionCreateFolder: '您沒有建立資料夾的權限',
+ noPermissionUpload: '您沒有上傳檔案的權限',
+ noPermissionMoveFiles: '您沒有移動檔案的權限',
+ noPermissionDeleteFiles: '您沒有刪除檔案的權限',
+ // External folder
+ linkExternal: '連結外部',
+ linkExternalFolder: '連結外部資料夾',
+ linkExternalFolderDescription: '將主機目錄(NAS、USB、網路共享)掛載到檔案管理器中。檔案不會被複制——直接從原始路徑存取。',
+ externalFolderNamePlaceholder: '例如:NAS列印檔案',
+ externalPath: '主機路徑',
+ externalPathHelp: 'Docker主機上目錄的絕對路徑。必須以繫結掛載方式掛載到容器中。',
+ readOnly: '只讀',
+ readOnlyHelp: '防止上傳和刪除',
+ showHiddenFiles: '顯示隱藏檔案(點檔案)',
+ externalFolder: '外部資料夾',
+ scanFolder: '掃描',
+ toast: {
+ folderCreated: '資料夾已建立',
+ folderDeleted: '資料夾已刪除',
+ fileDeleted: '檔案已刪除',
+ filesDeleted: '已刪除 {{count}} 個檔案',
+ filesMoved: '檔案已移動',
+ folderLinked: '資料夾已連結',
+ folderUnlinked: '資料夾已取消連結',
+ externalFolderLinked: '外部資料夾已連結並掃描',
+ folderScanned: '掃描完成:新增 {{added}} 個,移除 {{removed}} 個',
+ addedToQueue: '已將 {{count}} 個檔案新增到佇列',
+ addedToQueuePartial: '已新增 {{added}} 個檔案,{{failed}} 個失敗',
+ failedToAddToQueue: '新增檔案失敗:{{error}}',
+ fileRenamed: '檔案已重新命名',
+ folderRenamed: '資料夾已重新命名',
+ thumbnailsGenerated: '已產生 {{count}} 個縮圖',
+ thumbnailsGeneratedPartial: '已產生 {{succeeded}} 個縮圖,{{failed}} 個失敗',
+ noStlMissingThumbnails: '沒有缺少縮圖的 STL 檔案',
+ failedToGenerateThumbnails: '產生縮圖失敗:{{error}}',
+ thumbnailGenerated: '縮圖已產生',
+ failedToGenerateThumbnail: '產生縮圖失敗:{{error}}',
+ },
+ },
+
+ // Projects
+ projects: {
+ title: '專案',
+ subtitle: '組織和追蹤您的 3D 列印專案',
+ newProject: '新增專案',
+ editProject: '編輯專案',
+ deleteProject: '刪除專案',
+ projectName: '專案名稱',
+ description: '描述',
+ noProjects: '尚無專案',
+ noProjectsFiltered: '沒有{{status}}專案',
+ noProjectsFilteredHelp: '您沒有任何{{status}}專案。當專案狀態更改時,它們將出現在這裡。',
+ createFirst: '建立您的第一個項目以開始組織相關列印、追蹤進度和管理構建。',
+ createFirstButton: '建立您的第一個項目',
+ create: '建立',
+ files: '檔案',
+ prints: '列印',
+ plates: '板',
+ parts: '零件',
+ lastModified: '最後修改',
+ deleteConfirm: '確定要刪除此項目嗎?歸檔和佇列項目將被取消連結但不會被刪除。',
+ addFiles: '新增檔案',
+ removeFile: '移除檔案',
+ viewDetails: '檢視詳情',
+ // Modal fields
+ namePlaceholder: '例如:Voron 2.4 構建',
+ descriptionPlaceholder: '可選描述...',
+ color: '顏色',
+ targetPlates: '目標板數',
+ targetPlatesPlaceholder: '例如:25',
+ targetPlatesHelp: '列印任務數量',
+ targetParts: '目標零件數',
+ targetPartsPlaceholder: '例如:150',
+ targetPartsHelp: '所需零件總數',
+ tagsLabel: '標籤(逗號分隔)',
+ tagsPlaceholder: '例如:voron、功能件、禮物',
+ dueDate: '截止日期',
+ priority: '優先順序',
+ priorityLow: '低',
+ priorityNormal: '普通',
+ priorityHigh: '高',
+ priorityUrgent: '緊急',
+ // Status
+ statusActive: '進行中',
+ statusCompleted: '已完成',
+ statusArchived: '已歸檔',
+ done: '完成',
+ completed: '已完成',
+ failed: '失敗',
+ inQueue: '佇列中',
+ noPrintsYet: '尚無列印',
+ // Footer stats
+ printJobs: '列印任務(板)',
+ partsPrinted: '已列印零件',
+ failedParts: '失敗零件',
+ // Actions
+ import: '匯入',
+ export: '匯出',
+ importProject: '匯入專案',
+ exportAll: '匯出所有專案',
+ loading: '載入專案中...',
+ // Permissions
+ noEditPermission: '您沒有編輯專案的權限',
+ noDeletePermission: '您沒有刪除專案的權限',
+ noCreatePermission: '您沒有建立專案的權限',
+ noImportPermission: '您沒有匯入專案的權限',
+ noExportPermission: '您沒有匯出專案的權限',
+ // Toast
+ toast: {
+ created: '專案已建立',
+ updated: '專案已更新',
+ deleted: '專案已刪除',
+ imported: '專案已匯入',
+ multipleImported: '已匯入 {{count}} 個項目',
+ importFailed: '匯入失敗',
+ exported: '專案已匯出(僅中繼資料)',
+ },
+ },
+
+ // Project detail page
+ projectDetail: {
+ notFound: '未找到專案',
+ backToProjects: '返回專案',
+ export: '匯出',
+ exportProject: '匯出專案',
+ noExportPermission: '您沒有匯出專案的權限',
+ noEditPermission: '您沒有編輯專案的權限',
+ partOf: '屬於:',
+ priorityLabel: '優先順序:',
+ noPrints: '此項目尚無列印',
+ status: {
+ active: '進行中',
+ completed: '已完成',
+ archived: '已歸檔',
+ },
+ priority: {
+ low: '低',
+ normal: '普通',
+ high: '高',
+ urgent: '緊急',
+ },
+ dueDate: {
+ overdue: '已逾期',
+ today: '今天到期',
+ daysLeft: '還有 {{count}} 天',
+ },
+ progress: {
+ platesProgress: '板進度',
+ partsProgress: '零件進度',
+ printJobs: '列印任務',
+ parts: '零件',
+ percentComplete: '{{percent}}% 完成',
+ remaining: '剩餘 {{count}} 個',
+ },
+ stats: {
+ printJobs: '列印任務',
+ total: '總計',
+ failed: '{{count}} 個失敗',
+ partsPrinted: '已列印 {{count}} 個零件',
+ printTime: '列印時間',
+ filamentUsed: '耗材用量',
+ },
+ cost: {
+ title: '成本追蹤',
+ filamentCost: '耗材成本',
+ energy: '能源',
+ totalCost: '總成本',
+ total: '總計',
+ includesBom: '含物料清單',
+ budget: '預算',
+ remaining: '剩餘',
+ },
+ subProjects: {
+ title: '子專案 ({{count}})',
+ },
+ notes: {
+ title: '備註',
+ noEditPermission: '您沒有編輯備註的權限',
+ placeholder: '新增關於此項目的備註...',
+ empty: '尚無備註。點選編輯新增備註。',
+ },
+ files: {
+ title: '檔案',
+ linkFolders: '從檔案管理器連結資料夾',
+ forQuickAccess: '到此項目以便快速存取。',
+ fileCount: '{{count}} 個檔案',
+ empty: '未連結資料夾。前往檔案管理器將資料夾連結到此項目。',
+ noFiles: '此資料夾中沒有檔案。',
+ print: '立即列印',
+ addToQueue: '加入佇列',
+ },
+ bom: {
+ title: '材料清單',
+ acquired: '已獲取 {{completed}}/{{total}}',
+ showAll: '顯示全部',
+ hideDone: '隱藏已完成',
+ addPart: '新增零件',
+ noAddPermission: '您沒有新增零件的權限',
+ partNamePlaceholder: '零件名稱(例如:M3x8 螺絲)',
+ partName: '零件名稱',
+ qty: '數量',
+ price: '價格 ({{currency}})',
+ sourcingUrlPlaceholder: '採購連結(可選)',
+ remarksPlaceholder: '備註(可選)',
+ deletePart: '刪除零件',
+ deleteConfirm: '確定要刪除"{{name}}"嗎?',
+ noUpdatePermission: '您沒有更新零件的權限',
+ noEditPermission: '您沒有編輯零件的權限',
+ noDeletePermission: '您沒有刪除零件的權限',
+ totalCost: '總成本:',
+ empty: '材料清單中沒有零件。新增硬體、電子元件或其他元件以追蹤需要採購的物品。',
+ },
+ timeline: {
+ title: '活動時間線',
+ empty: '尚無活動。',
+ },
+ template: {
+ saveAsTemplate: '儲存為範本',
+ noCreatePermission: '您沒有建立範本的權限',
+ },
+ queue: {
+ title: '佇列',
+ viewAll: '檢視全部',
+ printing: '{{count}} 個列印中',
+ queued: '{{count}} 個佇列中',
+ },
+ prints: {
+ title: '列印 ({{count}})',
+ },
+ toast: {
+ projectUpdated: '專案已更新',
+ partAdded: '零件已新增',
+ partRemoved: '零件已移除',
+ exportFailed: '匯出失敗',
+ projectExported: '專案已匯出',
+ templateCreated: '範本已建立',
+ },
+ },
+
+ // System info
+ system: {
+ title: '系統資訊',
+ version: '版本',
+ uptime: '執行時間',
+ cpuUsage: 'CPU 使用率',
+ memoryUsage: '記憶體使用率',
+ diskUsage: '磁碟使用率',
+ networkInfo: '網路資訊',
+ logs: '日誌',
+ debugMode: '偵錯模式',
+ enableDebug: '啟用偵錯日誌',
+ disableDebug: '停用偵錯日誌',
+ downloadLogs: '下載日誌',
+ clearLogs: '清除日誌',
+ dockerInfo: 'Docker 資訊',
+ containerName: '容器名稱',
+ imageName: '映象名稱',
+ platform: '平臺',
+ architecture: '架構',
+ },
+
+ // Library (K Profiles)
+ library: {
+ title: '耗材庫',
+ addFilament: '新增耗材',
+ editFilament: '編輯耗材',
+ deleteFilament: '刪除耗材',
+ vendor: '廠商',
+ material: '材料',
+ color: '顏色',
+ kFactor: 'K 值',
+ temperature: '溫度',
+ noFilaments: '耗材庫中沒有耗材',
+ deleteConfirm: '確定要刪除此耗材嗎?',
+ importFromPrinter: '從印表機匯入',
+ exportToFile: '匯出到檔案',
+ },
+
+ // Spoolman
+ spoolman: {
+ title: 'Spoolman 整合',
+ enabled: 'Spoolman 已啟用',
+ url: 'Spoolman URL',
+ connected: '已連線',
+ disconnected: '未連線',
+ testConnection: '測試連線',
+ sync: '同步',
+ syncing: '同步中...',
+ lastSync: '上次同步',
+ linkToSpoolman: '連結到 Spoolman',
+ openInSpoolman: '在 Spoolman 中開啟',
+ unlinkSpool: '取消連結耗材',
+ unlinkConfirmTitle: '解開料盤?',
+ unlinkConfirmMessage: '這將斷開卷軸與 Spoolman 的連線。Spoolman 中的卷軸資料將保持不變。',
+ selectSpool: '選擇耗材',
+ noUnlinkedSpools: '無未連結的耗材',
+ linkSuccess: '耗材已成功連結到 Spoolman',
+ linkFailed: '連結耗材失敗',
+ unlinkSuccess: '已成功從 Spoolman 取消連結耗材',
+ unlinkFailed: '取消連結耗材失敗',
+ spoolId: '耗材 ID',
+ fillSourceLabel: '(Spoolman)',
+ weight: '重量',
+ remaining: '剩餘',
+ disableWeightSync: '停用 AMS 估計重量同步',
+ disableWeightSyncDesc: '不從 AMS 估計值更新剩餘容量。如果您更喜歡 Spoolman 的用量追蹤而非 AMS 百分比估計,請使用此選項。新耗材仍將使用 AMS 估計值作為初始重量。',
+ reportPartialUsage: '報告失敗列印的部分用量',
+ reportPartialUsageDesc: '當列印失敗或被取消時,根據層進度報告估計的耗材使用量。',
+ },
+
+ // Inventory
+ inventory: {
+ title: '耗材庫存',
+ addSpool: '新增耗材',
+ editSpool: '編輯耗材',
+ material: '材料',
+ selectMaterial: '選擇材料...',
+ subtype: '子類型',
+ brand: '品牌',
+ searchBrand: '搜尋品牌...',
+ useCustomBrand: '使用"{{brand}}"',
+ useCustomMaterial: '使用自訂材料:{{material}}',
+ colorName: '顏色名稱',
+ colorNamePlaceholder: '翡翠白、烈焰紅...',
+ color: '顏色',
+ hexColor: '十六進位顏色',
+ pickColor: '選擇自訂顏色',
+ labelWeight: '標籤重量',
+ coreWeight: '空盤重量',
+ searchSpoolWeight: '搜尋耗材重量...',
+ weightUsed: '已使用',
+ currentWeight: '剩餘重量',
+ measuredWeight: '稱量重量',
+ spoolName: '料盤',
+ costPerKg: '每公斤成本',
+ measuredWeightError: '稱量重量必須在 {{min}}g 到 {{max}}g 之間。',
+ slicerFilament: '切片耗材',
+ slicerFilamentName: '切片預設名稱',
+ slicerPreset: '切片預設',
+ searchPresets: '搜尋耗材預設...',
+ selectedPreset: '已選擇',
+ noPresetsFound: '未找到預設',
+ tempOverrides: '溫度覆蓋',
+ note: '備註',
+ notePlaceholder: '關於此耗材的任何備註...',
+ archive: '歸檔',
+ restore: '恢復',
+ noSpools: '尚無耗材。新增您的第一個耗材開始使用。',
+ noManualSpools: '沒有手動新增的耗材。請先向庫存中新增耗材。',
+ kProfiles: 'K 值設定',
+ addKProfile: '新增 K 值設定',
+ assignSpool: '分配耗材',
+ unassignSpool: '取消分配',
+ assignSuccess: '耗材已分配,AMS 槽位已設定',
+ assignFailed: '分配耗材失敗',
+ assignMismatchTitle: '材料不符',
+ assignMismatchMessage: '所選料盤材料 "{{spoolMaterial}}" 與 {{location}} 的料槽材料 "{{trayMaterial}}" 不符。仍要分配嗎?',
+ assignMismatchConfirm: '仍然分配',
+ assignPartialMismatchMessage: '料盤材料 "{{spoolMaterial}}" 與 {{location}} 的 "{{trayMaterial}}" 相近但不完全一致。是否繼續?',
+ assignProfileMismatchMessage: '料盤設定 "{{spoolProfile}}" 與 {{location}} 的料槽設定 "{{trayProfile}}" 不一致。是否繼續?',
+ selectSpool: '選擇要分配到此槽位的耗材',
+ assigned: '已分配',
+ assigning: '分配中...',
+ searchSpools: '搜尋耗材...',
+ showAllSpools: '顯示所有耗材',
+ allMaterials: '所有材料',
+ filterByBrand: '按品牌篩選...',
+ showArchived: '顯示已歸檔',
+ quickAdd: '快速新增(庫存)',
+ quantity: '數量',
+ stock: '庫存',
+ configured: '已設定',
+ spoolsCreated: '已建立 {{count}} 個耗材',
+ spoolCreated: '耗材已建立',
+ spoolUpdated: '耗材已更新',
+ spoolDeleted: '耗材已刪除',
+ spoolArchived: '耗材已歸檔',
+ spoolRestored: '耗材已恢復',
+ deleteConfirm: '確定要刪除此耗材嗎?此操作無法復原。',
+ archiveConfirm: '確定要歸檔此耗材嗎?',
+ advancedSettings: '進階設定',
+ // Tabs
+ filamentInfoTab: '耗材資訊',
+ paProfileTab: 'PA 設定',
+ filamentInfo: '耗材',
+ additional: '附加',
+ // Cloud
+ loadingPresets: '載入雲端預設中...',
+ cloudConnected: '雲端已連線',
+ cloudNotConnected: '雲端未連線(使用預設值)',
+ // Colors
+ recentColors: '最近',
+ searchColors: '搜尋顏色...',
+ searchResults: '搜尋結果',
+ allColors: '所有顏色',
+ commonColors: '常用顏色',
+ showLess: '顯示更少',
+ showAll: '顯示全部',
+ noColorsFound: '沒有顏色匹配您的搜尋',
+ noResults: '未找到匹配項',
+ // PA Profiles
+ selectMaterialFirst: '請先在耗材資訊分頁中選擇材料。',
+ noPrintersConfigured: '未設定印表機。新增印表機以使用 PA 設定。',
+ matchingFilter: '匹配',
+ anyBrand: '任何品牌',
+ anyVariant: '任何變體',
+ autoSelect: '自動選擇',
+ matches: '匹配',
+ match: '匹配',
+ noMatches: '無匹配',
+ connected: '已連線',
+ offline: '離線',
+ printerOffline: '印表機離線。連線後檢視校準設定。',
+ noKProfilesMatch: '沒有 K 值設定匹配所選耗材。',
+ leftNozzle: '左噴嘴',
+ rightNozzle: '右噴嘴',
+ profilesSelected: '個校準設定已選擇',
+ // Stats & enhanced table
+ totalInventory: '總庫存',
+ totalConsumed: '總消耗',
+ byMaterial: '按材料',
+ inPrinter: '在印表機中',
+ lowStock: '庫存不足',
+ sinceTracking: '自開始追蹤',
+ loadedInAms: '已裝載到 AMS/外接',
+ remaining: '剩餘',
+ weightCheck: '重量檢查',
+ lastWeighed: '上次稱量',
+ neverWeighed: '從未稱量',
+ search: '搜尋耗材...',
+ showing: '顯示',
+ to: '到',
+ of: '共',
+ show: '顯示',
+ spools: '個耗材',
+ spool: '個耗材',
+ page: '頁',
+ noSpoolsMatch: '未找到結果',
+ noSpoolsMatchDesc: '嘗試調整您的搜尋或篩選條件。',
+ active: '活躍',
+ archived: '已歸檔',
+ all: '全部',
+ used: '已使用',
+ new: '新的',
+ clearFilters: '清除篩選',
+ table: '表格',
+ cards: '卡片',
+ net: '淨重',
+ // Grouping
+ groupSimilar: '分組',
+ groupedSpools: '{{count}} 個相同耗材',
+ groupedRows: '行',
+ // Column config
+ columns: '列',
+ configureColumns: '設定列',
+ configureColumnsDesc: '拖曳以重新排序列或使用箭頭。使用眼睛圖示切換可見性。',
+ visible: '可見',
+ reset: '重設',
+ cancel: '取消',
+ applyChanges: '套用更改',
+ moveUp: '上移',
+ moveDown: '下移',
+ hideColumn: '隱藏列',
+ showColumn: '顯示列',
+ // Tag linking
+ linkToSpool: '連結到耗材',
+ tagLinked: '標籤已連結到耗材',
+ tagLinkFailed: '連結標籤失敗',
+ tagAlreadyLinked: '標籤已連結到其他耗材',
+ unknownTag: '偵測到未知 RFID 標籤',
+ // Usage history
+ usageHistory: '使用歷史',
+ noUsageHistory: '尚無使用紀錄',
+ printName: '列印名稱',
+ weightConsumed: '消耗重量',
+ clearHistory: '清除',
+ historyCleared: '使用歷史已清除',
+ fillSourceLabel: '(庫存)',
+ lowStockThresholdError: '閾值必須在 0.1 到 99.9 之間',
+ },
+
+ // Timelapse
+ timelapse: {
+ title: '縮時攝影',
+ create: '建立縮時攝影',
+ download: '下載',
+ delete: '刪除',
+ preview: '預覽',
+ frameRate: '幀率',
+ quality: '品質',
+ processing: '處理中...',
+ noTimelapses: '無可用縮時攝影',
+ },
+
+ // AMS
+ ams: {
+ title: 'AMS',
+ slot: '槽位',
+ empty: '空',
+ emptySlot: '空槽位',
+ unknown: '未知',
+ humidity: '濕度',
+ temperature: '溫度',
+ filamentType: '耗材類型',
+ filamentColor: '顏色',
+ remaining: '剩餘',
+ history: 'AMS 歷史',
+ noHistory: '無可用歷史',
+ configureSlot: '設定槽位',
+ externalSpool: '外接耗材',
+ profile: '設定',
+ kFactor: 'K 值',
+ fill: '填充',
+ configure: '設定',
+ used: '已使用',
+ remainingUnit: '剩餘',
+ },
+
+ // Print modal
+ printModal: {
+ title: '開始列印',
+ selectPrinter: '選擇印表機',
+ selectPlate: '選擇板',
+ filamentMapping: '耗材對應',
+ totalCost: '總成本:',
+ slotRemainingShort: ' - 剩餘 {{grams}}g',
+ printSettings: '列印設定',
+ bedLeveling: '熱床調平',
+ flowCalibration: '流量校準',
+ vibrationCalibration: '振動校準',
+ layerInspection: '首層檢查',
+ timelapse: '縮時攝影',
+ startPrint: '開始列印',
+ addToQueue: '新增到佇列',
+ cancel: '取消',
+ noPrintersAvailable: '無可用印表機',
+ printerBusy: '印表機忙碌',
+ printerOffline: '印表機離線',
+ sameTypeDifferentColor: '相同類型,不同顏色',
+ filamentTypeNotLoaded: '耗材類型未裝載',
+ openCalendar: '開啟日曆',
+ leftNozzle: '左',
+ rightNozzle: '右',
+ leftNozzleTooltip: '左噴嘴',
+ rightNozzleTooltip: '右噴嘴',
+ filamentOverride: '耗材覆蓋',
+ filamentOverrideHint: '可選覆蓋用於基於模型的耗材分配。排程器將使用您選擇的耗材而不是原始 3MF 值進行匹配。',
+ originalFilament: '原始',
+ overrideWith: '覆蓋為',
+ resetToOriginal: '恢復為原始',
+ insufficientFilamentTitle: '耗材不足',
+ insufficientFilamentMessage: '部分已分配料盤的剩餘耗材少於本次列印所需:',
+ insufficientFilamentLine: '{{printer}} - {{slot}}:需要 {{required}}g,剩餘 {{remaining}}g',
+ printAnyway: '仍然列印',
+ forceColorMatch: '強制顏色匹配',
+ staggerPrinterStarts: '錯開印表機啟動',
+ staggerGroupSize: '群組大小',
+ staggerInterval: '間隔(分鐘)',
+ staggerPreview: '{{printers}} 台印表機 → 分成 {{groups}} 組,每組 {{size}} 台,每 {{interval}} 分鐘啟動一組',
+ staggerLastGroup: '最後一組:{{count}}',
+ staggerTotal: '總計:{{minutes}} 分鐘',
+ staggerToPrinters: '分批傳送到 {{count}} 臺印表機',
+ gcodeInjection: '注入自動列印G-code',
+ },
+
+ // Backup
+ backup: {
+ title: '備份與恢復',
+ createBackup: '建立備份',
+ restoreBackup: '恢復備份',
+ restoreDescription: '從備份檔案替換所有資料',
+ downloadBackup: '下載備份',
+ uploadBackup: '上傳備份',
+ lastBackup: '上次備份',
+ autoBackup: '自動備份',
+ backupNow: '立即備份',
+ restoreWarning: '警告:恢復備份將覆蓋所有目前資料。',
+ includeArchives: '包含歸檔',
+ includeSettings: '包含設定',
+ includeProfiles: '包含設定檔案',
+ backupSuccess: '備份建立成功',
+ restoreSuccess: '備份恢復成功',
+ backupFailed: '備份失敗',
+ restoreFailed: '恢復失敗',
+ restoreNote: '恢復期間虛擬印表機將停止',
+
+ // GitHub Backup
+ githubBackup: 'GitHub 備份',
+ enabled: '已啟用',
+ cloudLoginRequired: '需要登入 Bambu Cloud。請在 設定檔案 → 雲設定檔案 中登入以啟用 GitHub 備份。',
+ cloudLoginRequiredShort: '需要雲端登入',
+ githubDescription: '自動將您的設定檔案同步到私有 GitHub 倉庫以進行備份和版本歷史紀錄。',
+ repositoryUrl: '倉庫 URL',
+ personalAccessToken: '個人存取權杖',
+ tokenSaved: '(已儲存)',
+ enterNewToken: '輸入新權杖以更新',
+ tokenHint: '具有內容讀寫權限的細粒度權杖',
+ branch: '分支',
+ manualOnly: '僅手動',
+ hourly: '每小時',
+ daily: '每天',
+ weekly: '每週',
+ includeInBackup: '包含在備份中',
+ kProfiles: 'K 設定檔案',
+ kProfilesDescription: '來自已連線印表機的壓力推進校準',
+ noPrintersConnected: '沒有印表機連線',
+ printersConnected: '{{connected}}/{{total}} 已連線',
+ cloudProfiles: '雲設定檔案',
+ cloudProfilesDescription: '來自 Bambu Cloud 的耗材、印表機和工藝預設',
+ appSettings: '應用程式設定',
+ appSettingsDescription: 'Bambuddy 設定(完整資料庫)',
+ spoolInventory: '耗材庫存',
+ spoolInventoryDescription: '耗材卷軸、使用紀錄和成本追蹤',
+ printArchives: '列印檔案',
+ printArchivesDescription: '列印歷史中繼資料(不含 gcode/3MF 檔案)',
+ lastBackupAt: '上次備份:',
+ noBackupsYet: '尚無備份',
+ next: '下次:',
+ startingBackup: '正在啟動備份...',
+ test: '測試',
+ enableBackup: '啟用備份',
+ testConnection: '測試連線',
+ enterRepoUrl: '請輸入倉庫 URL',
+ enterRepoAndToken: '請輸入倉庫 URL 和存取權杖',
+ repoRequired: '倉庫 URL 為必填項',
+ tokenRequired: '存取權杖為必填項',
+ githubBackupEnabled: 'GitHub 備份已啟用',
+ tokenUpdated: '權杖已更新',
+ settingsSaved: '設定已儲存',
+ failedToSave: '儲存失敗:{{message}}',
+ backupCompleteFiles: '備份完成 - {{count}} 個檔案已更新',
+ backupSkippedNoChanges: '備份已跳過 - 無更改',
+ backupFailed2: '備份失敗:{{message}}',
+ clearedLogs: '已清除 {{count}} 條日誌',
+ failedToClearLogs: '清除日誌失敗:{{message}}',
+
+ // History
+ history: '歷史紀錄',
+ clear: '清除',
+ date: '日期',
+ status: '狀態',
+ commit: '提交',
+
+ // Local Backup
+ localBackup: '本機備份',
+ localBackupDescription: '建立 Bambuddy 資料的完整備份,包括資料庫、檔案、上傳和所有檔案。',
+ downloadBackupLabel: '下載備份',
+ completeBackupZip: '完整備份:資料庫 + 所有檔案(ZIP)',
+ download: '下載',
+ preparingBackup: '正在準備備份...',
+ creatingArchive: '正在建立備份歸檔...對於大型歸檔可能需要一些時間。',
+ downloadingFile: '正在下載備份檔案...',
+ backupDownloaded: '備份下載成功',
+ failedToCreateBackup: '建立備份失敗:{{message}}',
+ restore: '恢復',
+ restoreReplacesAll: '恢復將替換所有資料。',
+ restoreReplacesAllDetail: '您目前的資料庫和檔案將被完全替換。恢復後需要重新啟動。',
+ restoreConfirmTitle: '恢復備份',
+ restoreConfirmMessage: '您確定要從"{{filename}}"恢復嗎?這將完全替換您目前的資料庫和所有檔案。恢復後需要重新啟動應用程式。',
+ restoreConfirmButton: '恢復備份',
+ uploadingFile: '正在上傳備份檔案...',
+ backupRestoredRestart: '備份已恢復。請重新啟動 Bambuddy。',
+ failedToRestore: '恢復備份失敗。請檢查檔案格式。',
+ reloadNow: '立即重新載入',
+ creatingBackup: '正在建立備份',
+ restoringBackup: '正在恢復備份',
+ preparing: '準備中...',
+ processing: '處理中...',
+ doNotClosePage: '請不要關閉此頁面或離開頁面。對於大型備份,此操作可能需要幾分鐘。',
+
+ // RestoreModal
+ restoring: '恢復中...',
+ restoreComplete: '恢復完成',
+ restoreFailed2: '恢復失敗',
+ importSettings: '從備份檔案匯入設定',
+ pleaseWaitRestoring: '請等待資料恢復中',
+ selectBackupFile: '點選選擇備份檔案(.json 或 .zip)',
+ duplicateHandling: '重複項處理方式:',
+ matchPrinters: '印表機',
+ matchPrintersBy: '按序列號匹配',
+ matchSmartPlugs: '智慧插座',
+ matchSmartPlugsBy: '按 IP 位址匹配',
+ matchNotificationProviders: '通知提供者',
+ matchNotificationProvidersBy: '按名稱匹配',
+ matchFilaments: '耗材',
+ matchFilamentsBy: '按名稱 + 類型 + 品牌匹配',
+ matchArchives: '檔案',
+ matchArchivesBy: '按內容雜湊匹配(始終跳過)',
+ matchPendingUploads: '待上傳',
+ matchPendingUploadsBy: '按檔名匹配',
+ matchSettingsTemplates: '設定和範本',
+ matchSettingsTemplatesBy: '始終覆蓋',
+ replaceExisting: '替換現有資料',
+ keepExisting: '保留現有資料',
+ overwriteDescription: '用備份資料覆蓋已存在的項目',
+ keepDescription: '僅恢復尚不存在的項目',
+ overwriteCaution: '注意:',
+ overwriteWarning: '覆蓋將用備份資料替換您目前的設定。出於安全考慮,印表機存取碼永遠不會被覆蓋。',
+ cancel: '取消',
+ processingBackup: '正在處理備份檔案...',
+ itemsRestored: '已恢復項目',
+ itemsSkipped: '已跳過項目',
+ restored: '已恢復',
+ skippedAlreadyExist: '已跳過(已存在)',
+ filesCategory: '檔案(3MF、縮圖等)',
+ andMore: '...還有 {{count}} 項',
+ newApiKeysGenerated: '已產生新的 API 金鑰',
+ keysShownOnce: '這些金鑰僅顯示一次。請立即複製!',
+ copy: '複製',
+ noDataFound: '在備份檔案中未找到可恢復的資料。',
+ close: '關閉',
+
+ // Scheduled local backups (#884)
+ scheduledBackup: '排程備份',
+ scheduledBackupDescription: '依排程自動建立備份快照。輸出目錄可掛載到 NAS 或外部儲存。',
+ frequency: '頻率',
+ backupTime: '時間',
+ retention: '保留',
+ retentionDescription: '保留的備份數量',
+ outputPath: '輸出路徑',
+ outputPathPlaceholder: '預設:{{path}}',
+ outputPathDescription: '留空以使用預設位置',
+ runNow: '立即執行',
+ backupFiles: '備份檔案',
+ noScheduledBackups: '尚無備份',
+ deleteBackup: '刪除',
+ deleteBackupConfirm: '要刪除此備份檔案嗎?',
+ backupRunning: '備份進行中…',
+ scheduledBackupComplete: '備份已成功完成',
+ scheduledBackupFailed: '備份失敗',
+ nextBackup: '下次備份',
+ backupSize: '大小',
+ utc: 'UTC',
+ defaultPathLabel: '預設:',
+
+ // Category labels
+ categories: {
+ settings: '設定',
+ notification_providers: '通知提供者',
+ notification_templates: '通知範本',
+ smart_plugs: '智慧插座',
+ printers: '印表機',
+ filaments: '耗材',
+ maintenance_types: '維護類型',
+ archives: '檔案',
+ projects: '專案',
+ pending_uploads: '待上傳',
+ external_links: '外部連結',
+ api_keys: 'API 金鑰',
+ },
+ },
+
+ // Tags
+ tags: {
+ title: '標籤',
+ addTag: '新增標籤',
+ editTag: '編輯標籤',
+ deleteTag: '刪除標籤',
+ tagName: '標籤名稱',
+ tagColor: '標籤顏色',
+ noTags: '無標籤',
+ deleteConfirm: '確定要刪除此標籤嗎?',
+ manageTags: '管理標籤',
+ },
+
+ // Upload modal (archives)
+ uploadModal: {
+ title: '上傳 3MF 檔案',
+ dragDrop: '將 .3mf 檔案拖放到此處',
+ or: '或',
+ browseFiles: '瀏覽檔案',
+ extractionInfo: '將從 3MF 檔案中繼資料中自動提取印表機型號。',
+ uploaded: '已上傳',
+ failed: '失敗',
+ uploading: '上傳中...',
+ upload: '上傳',
+ uploadFailed: '上傳失敗',
+ },
+
+ // Edit archive modal
+ // Edit Archive Modal
+ editArchive: {
+ title: '編輯歸檔',
+ name: '名稱',
+ namePlaceholder: '列印名稱',
+ printer: '印表機',
+ noPrinter: '無印表機',
+ project: '專案',
+ noProject: '無專案',
+ itemsPrinted: '列印數量',
+ itemsPrintedHelp: '此列印任務中生產的物品數量',
+ notes: '備註',
+ notesPlaceholder: '新增關於此列印的備註...',
+ externalLink: '外部連結',
+ externalLinkPlaceholder: 'https://printables.com/model/...',
+ externalLinkHelp: '連結到 Printables、Thingiverse 或其他來源',
+ tags: '標籤',
+ tagsPlaceholder: '新增標籤...',
+ addMoreTags: '新增更多標籤...',
+ matchingTags: '匹配"{{query}}"',
+ existingTags: '現有標籤',
+ clickToAdd: '(點選新增)',
+ status: '狀態',
+ failureReason: '失敗原因',
+ selectReason: '選擇原因...',
+ photos: '列印成品照片',
+ photosHelp: '點選 + 新增列印成品照片',
+ printResult: '列印成品',
+ saving: '儲存中...',
+ // Failure reasons
+ failureReasons: {
+ adhesionFailure: '附著力失敗',
+ spaghettiDetached: '拉絲 / 脫落',
+ layerShift: '層偏移',
+ cloggedNozzle: '噴嘴堵塞',
+ filamentRunout: '耗材用完',
+ warping: '翹曲',
+ stringing: '拉絲',
+ underExtrusion: '擠出不足',
+ powerFailure: '斷電',
+ userCancelled: '使用者取消',
+ other: '其他',
+ },
+ // Archive statuses
+ statuses: {
+ completed: '已完成',
+ failed: '失敗',
+ aborted: '已取消',
+ printing: '列印中',
+ },
+ },
+
+ // K-Profiles
+ kProfiles: {
+ title: 'K 值設定',
+ noPrintersConfigured: '未設定印表機',
+ addPrinterInSettings: '在設定中新增印表機以管理 K 值設定',
+ noActivePrinters: '無活躍印表機',
+ enablePrinterConnection: '啟用印表機連線以檢視其 K 值設定',
+ loadingProfiles: '載入 K 值設定中...',
+ printerOffline: '印表機離線',
+ printerOfflineDesc: '所選印表機未連線。開啟電源以檢視 K 值設定。',
+ noMatchingProfiles: '無匹配的設定',
+ noMatchingProfilesDesc: '沒有設定匹配您的搜尋條件',
+ noKProfiles: '無 K 值設定',
+ noKProfilesDesc: '未找到 {{diameter}}mm 噴嘴的壓力推進設定',
+ createFirstProfile: '建立第一個設定',
+ // Controls
+ printer: '印表機',
+ nozzle: '噴嘴',
+ refresh: '重新整理',
+ addProfile: '新增設定',
+ export: '匯出',
+ import: '匯入',
+ select: '選擇',
+ selectAll: '全選',
+ delete: '刪除',
+ // Filters
+ searchPlaceholder: '按名稱或耗材搜尋...',
+ allExtruders: '所有擠出機',
+ leftOnly: '僅左側',
+ rightOnly: '僅右側',
+ allFlow: '所有流量',
+ hfOnly: '僅高流量',
+ sOnly: '僅標準',
+ sortName: '排序:名稱',
+ sortKValue: '排序:K 值',
+ sortFilament: '排序:耗材',
+ // Dual extruder labels
+ leftExtruder: '左擠出機',
+ rightExtruder: '右擠出機',
+ // Modal
+ modal: {
+ addTitle: '新增 K 值設定',
+ editTitle: '編輯 K 值設定',
+ profileName: '設定名稱',
+ profileNamePlaceholder: '我的 PLA 設定',
+ kValue: 'K 值',
+ kValuePlaceholder: '0.020',
+ kValueHelp: '典型範圍:PLA 0.01 - 0.06,PETG 0.02 - 0.10',
+ filament: '耗材',
+ selectFilament: '選擇耗材...',
+ noFilamentsHelp: '未找到耗材。請先在 Bambu Studio 中建立 K 值設定。',
+ flowType: '流量類型',
+ highFlow: '高流量',
+ standard: '標準',
+ nozzleSize: '噴嘴尺寸',
+ extruder: '擠出機',
+ extruders: '擠出機',
+ left: '左',
+ right: '右',
+ notes: '備註(本機儲存)',
+ notesPlaceholder: '新增關於此設定的備註...',
+ notesHelp: '備註儲存在 Bambuddy 中,不在印表機上',
+ syncing: '與印表機同步中...',
+ savingExtruder: '儲存到擠出機 {{current}}/{{total}}...',
+ pleaseWait: '請稍候',
+ },
+ // Delete confirmation
+ deleteConfirm: {
+ title: '刪除設定',
+ cannotUndo: '此操作無法復原',
+ message: '確定要從印表機刪除"{{name}}"嗎?',
+ },
+ // Bulk delete
+ bulkDelete: {
+ title: '刪除設定',
+ cannotUndo: '此操作無法復原',
+ message: '確定要從印表機刪除 {{count}} 個選中的設定嗎?',
+ },
+ // Toast
+ toast: {
+ profileSaved: 'K 值設定已儲存',
+ profilesSaved: 'K 值設定已儲存到 {{count}} 個擠出機',
+ selectAtLeastOneExtruder: '請至少選擇一個擠出機',
+ profileDeleted: 'K 值設定已刪除',
+ profilesDeleted: '已刪除 {{count}} 個設定',
+ exportedProfiles: '已匯出 {{count}} 個設定',
+ importedProfiles: '已匯入 {{count}} / {{total}} 個設定',
+ noProfilesToExport: '無可匯出的設定',
+ invalidFileFormat: '無效的檔案格式',
+ failedToParseImport: '解析匯入檔案失敗',
+ failedToSaveBatch: '批次儲存 K 值設定失敗',
+ noteSaved: '備註已儲存',
+ failedToSaveNote: '儲存備註失敗',
+ },
+ // Permissions
+ permission: {
+ noRead: '您沒有重新整理設定的權限',
+ noCreate: '您沒有新增設定的權限',
+ noUpdate: '您沒有更新 K 值設定的權限',
+ noDelete: '您沒有刪除 K 值設定的權限',
+ noExport: '您沒有匯出設定的權限',
+ noImport: '您沒有匯入設定的權限',
+ },
+ },
+
+ // Virtual Printer
+ virtualPrinter: {
+ title: '虛擬印表機',
+ running: '執行中',
+ stopped: '已停止',
+ description: {
+ default: '啟用虛擬印表機,使其在 Bambu Studio 和 OrcaSlicer 中可見。傳送到此印表機的檔案將直接歸檔而不列印。',
+ proxy: '啟用代理,將切片軟體流量中繼到真實印表機,允許在任何網路上遠端列印。',
+ },
+ enable: {
+ title: '啟用虛擬印表機',
+ visibleInSlicer: '在切片軟體發現中顯示為"Bambuddy"',
+ proxyingTo: '代理到 {{name}}',
+ notActive: '未啟用',
+ },
+ model: {
+ title: '印表機型號',
+ description: '選擇要模擬的印表機型號。',
+ restartWarning: '更改型號將重新啟動虛擬印表機',
+ },
+ accessCode: {
+ title: '存取碼',
+ isSet: '存取碼已設定',
+ notSet: '未設定存取碼 - 需要設定才能啟用',
+ placeholder: '輸入 8 位字元程式碼',
+ placeholderChange: '輸入新程式碼以更改',
+ hint: '必須恰好 8 個字元。切片軟體使用此程式碼進行認證。',
+ charCount: '({{count}}/8)',
+ },
+ targetPrinter: {
+ title: '目標印表機',
+ configured: '代理目標已設定',
+ notConfigured: '未選擇目標印表機 - 代理模式需要設定',
+ placeholder: '選擇印表機...',
+ hint: '選擇要將切片軟體流量代理到的印表機。印表機必須處於區域網路模式。',
+ noPrinters: '未設定印表機。請先新增印表機以使用代理模式。',
+ },
+ remoteInterface: {
+ title: '網路介面覆蓋',
+ configured: '介面覆蓋已啟用',
+ optional: '可選 - 當自動檢測的 IP 不正確時使用(例如多網路卡、Docker、VPN)',
+ placeholder: '自動檢測(預設)...',
+ hint: '覆蓋透過 SSDP 廣播並在 TLS 憑證中使用的 IP 位址。在 Bambuddy 有多個網路介面時很有用。',
+ },
+ mode: {
+ title: '模式',
+ archive: '歸檔',
+ archiveDesc: '立即歸檔檔案',
+ review: '審核',
+ reviewDesc: '歸檔前審核',
+ queue: '佇列',
+ queueDesc: '歸檔並新增到佇列',
+ proxy: '代理',
+ proxyDesc: '中繼到真實印表機',
+ },
+ autoDispatch: {
+ title: '自動派發',
+ description: '新增到佇列時自動開始列印。關閉後,列印任務等待手動派發。',
+ },
+ setupRequired: {
+ title: '需要設定',
+ description: '虛擬印表機功能需要額外的系統設定才能工作。包括埠轉發、防火牆規則和平臺特定設定。',
+ readGuide: '啟用前請閱讀設定指南',
+ },
+ howItWorks: {
+ title: '工作原理',
+ step1: '在同一區域網路中,虛擬印表機會透過發現機制自動出現在您的切片軟體(Bambu Studio / OrcaSlicer)中。從其他網路,透過 IP 位址和存取碼手動新增。',
+ step2: '在歸檔、審核和佇列模式下,使用切片軟體中的"傳送"按鈕將 3MF 檔案上傳到 Bambuddy。切片軟體會顯示"列印成功"— 檔案已儲存,未列印。',
+ step3: '在代理模式下,虛擬印表機將所有流量中繼到真實印表機 — 列印會立即開始,就像直接連線一樣。',
+ },
+ status: {
+ title: '狀態詳情',
+ printerName: '印表機名稱',
+ model: '型號',
+ serialNumber: '序列號',
+ mode: '模式',
+ pendingFiles: '待處理檔案',
+ targetPrinter: '目標印表機',
+ ftpPort: 'FTP 連接埠',
+ mqttPort: 'MQTT 連接埠',
+ ftpConnections: 'FTP 連線',
+ mqttConnections: 'MQTT 連線',
+ },
+ toast: {
+ updated: '虛擬印表機設定已更新',
+ failedToUpdate: '更新設定失敗',
+ accessCodeRequired: '請先設定存取碼',
+ targetPrinterRequired: '請先選擇目標印表機',
+ bindIpRequired: '請先設定繫結 IP',
+ accessCodeEmpty: '存取碼不能為空',
+ accessCodeLength: '存取碼必須恰好 8 個字元',
+ created: '虛擬印表機已建立',
+ failedToCreate: '建立虛擬印表機失敗',
+ deleted: '虛擬印表機已刪除',
+ failedToDelete: '刪除虛擬印表機失敗',
+ },
+ list: {
+ title: '虛擬印表機',
+ add: '新增',
+ addFirst: '新增虛擬印表機',
+ empty: '未設定虛擬印表機。新增一個以開始使用。',
+ },
+ bindIp: {
+ title: '繫結介面',
+ placeholder: '選擇介面...',
+ hint: '此虛擬印表機繫結的網路介面。每臺印表機必須唯一。',
+ },
+ proxy: {
+ accessCodeHint: '在代理模式下,在切片軟體中使用目標印表機的存取碼。連線會透明轉發到真實印表機。',
+ },
+ addDialog: {
+ title: '新增虛擬印表機',
+ name: '名稱',
+ hint: '建立後可以設定存取碼、目標印表機和其他設定。',
+ create: '建立',
+ },
+ deleteConfirm: {
+ title: '刪除虛擬印表機',
+ message: '確定要刪除"{{name}}"嗎?這將停止此印表機的所有服務。',
+ },
+ },
+
+ // Model Viewer
+ modelViewer: {
+ openInSlicer: '在切片軟體中開啟',
+ tabs: {
+ model: '3D 模型',
+ gcode: 'G-code 預覽',
+ },
+ notAvailable: '不可用',
+ notSliced: '未切片',
+ plates: '板',
+ allPlates: '所有板',
+ plateNumber: '板 {{number}}',
+ plateCount: '{{count}} 個板',
+ plateCount_other: '{{count}} 個板',
+ objectCount: '{{count}} 個物件',
+ objectCount_other: '{{count}} 個物件',
+ filamentCount: '{{count}} 種耗材',
+ filamentCount_other: '{{count}} 種耗材',
+ eta: '預計 {{minutes}} 分鐘',
+ noPreview: '此檔案無可用預覽',
+ pagination: {
+ pageOf: '第 {{current}} / {{total}} 頁',
+ prev: '上一頁',
+ next: '下一頁',
+ },
+ errors: {
+ failedToLoad: '載入檔案失敗',
+ noMeshes: '3MF 檔案中未找到網格',
+ unsupportedFormat: '不支援的檔案格式',
+ },
+ },
+
+ // Maintenance type descriptions (built-in)
+ maintenanceDescriptions: {
+ lubricateCarbonRods: '在碳纖維杆上塗抹潤滑劑以確保順暢運動',
+ lubricateRails: '在線性導軌上塗抹潤滑劑以確保順暢運動',
+ cleanNozzle: '清潔熱端和噴嘴以防止堵塞',
+ checkBelts: '檢查皮帶張力以確保列印精度',
+ cleanBuildPlate: '清潔列印板以獲得更好的附著力',
+ checkExtruder: '檢查擠出機齒輪磨損情況',
+ checkCooling: '確保冷卻風扇正常工作',
+ generalInspection: '印表機綜合檢查',
+ cleanCarbonRods: '清潔碳纖維杆以減少摩擦',
+ lubricateSteelRods: '在鋼杆上塗抹潤滑劑以確保順暢運動',
+ cleanSteelRods: '清潔鋼杆以減少摩擦',
+ cleanLinearRails: '擦拭線性導軌以清除灰塵和碎屑',
+ checkPtfeTube: '檢查 PTFE 管的磨損或損壞',
+ replaceHepaFilter: '更換 HEPA 過濾器以保證空氣品質',
+ replaceCarbonFilter: '更換活性炭過濾器',
+ lubricateLeftNozzleRail: '潤滑左噴嘴導軌(H2 系列)',
+ },
+
+ // Smart Plugs
+ smartPlugs: {
+ offline: '離線',
+ admin: '管理',
+ openPlugAdminPage: '開啟插座管理頁面',
+ deleteSmartPlug: '刪除智慧插座',
+ turnOnSmartPlug: '開啟智慧插座',
+ turnOffSmartPlug: '關閉智慧插座',
+ turnOn: '開啟',
+ turnOff: '關閉',
+ addSmartPlug: {
+ scanningNetwork: '掃描網路中...',
+ chooseEntity: '選擇實體...',
+ connectionFailed: '連線失敗',
+ searchEntities: '搜尋實體...',
+ searchPowerSensors: '搜尋功率感測器...',
+ searchEnergySensors: '搜尋能量感測器...',
+ placeholders: {
+ plugName: '客廳插座',
+ mqttStateOnValue: 'ON、true、1',
+ mqttSameAsPower: '與功率主題相同,或不同',
+ },
+ },
+ // SmartPlugCard
+ linkedTo: '連結到:',
+ monitorOnly: '僅監控',
+ alerts: '警報',
+ scheduleOn: '開啟 {{time}}',
+ scheduleOff: '關閉 {{time}}',
+ on: '開啟',
+ off: '關閉',
+ power: '功率',
+ kwhToday: '今日kWh',
+ settings: '設定',
+ automationSettings: '自動化設定',
+ showInSwitchbar: '在開關欄顯示',
+ quickAccessSidebar: '從側邊欄快速存取',
+ enabled: '已啟用',
+ enableAutomation: '為此插座啟用自動化',
+ autoOn: '自動開啟',
+ autoOnDescription: '列印開始時開啟',
+ autoOff: '自動關閉',
+ autoOffDescription: '列印完成時關閉(一次性)',
+ autoOffPersistent: '保持啟用',
+ autoOffPersistentDescription: '在列印之間保持啟用而非一次性',
+ turnOffDelayMode: '關閉延遲模式',
+ time: '時間',
+ temp: '溫度',
+ delayMinutes: '延遲(分鐘)',
+ tempThreshold: '溫度閾值(°C)',
+ tempThresholdDescription: '當噴嘴冷卻到此溫度以下時關閉',
+ edit: '編輯',
+ deleteConfirm: '確定要刪除"{{name}}"嗎?此操作無法復原。',
+ turnOnConfirm: '確定要開啟"{{name}}"嗎?',
+ turnOffConfirm: '確定要關閉"{{name}}"嗎?這將切斷連線裝置的電源。',
+ failedToTurn: '無法{{action}}"{{name}}"',
+ unknown: '未知',
+ // AddSmartPlugModal
+ addTitle: '新增智慧插座',
+ editTitle: '編輯智慧插座',
+ stopScanning: '停止掃描',
+ discoverTasmota: '發現Tasmota裝置',
+ foundDevices: '找到{{count}}個裝置 - 點選選擇:',
+ noDevicesFound: '未在您的網路中找到Tasmota裝置',
+ haNotConfigured: 'Home Assistant未設定。請在以下位置設定',
+ haSettingsPath: '設定 → 網路 → Home Assistant',
+ selectEntity: '選擇實體 *',
+ ipAddress: 'IP 位址 *',
+ nameLabel: '名稱 *',
+ username: '使用者名稱',
+ password: '密碼',
+ authHint: '如果您的Tasmota裝置不需要認證,請留空',
+ linkToPrinter: '連結印表機',
+ noPrinter: '無印表機(僅手動控制)',
+ linkingDescription: '連結後可在列印開始/完成時自動開關',
+ powerAlerts: '功率警報',
+ alertAbove: '高於時警報(W)',
+ alertBelow: '低於時警報(W)',
+ alertDescription: '當電力消耗超過這些閾值時收到通知。留空以停用該方向。',
+ dailySchedule: '每日計畫',
+ turnOnAt: '開啟時間',
+ turnOffAt: '關閉時間',
+ scheduleDescription: '每天在這些時間自動開關插座。留空以跳過該操作。',
+ showOnPrinterCard: '在印表機卡片上顯示',
+ displayOnPrinterCard: '在印表機卡片上顯示按鈕',
+ connectedResult: '已連線!',
+ deviceLabel: '裝置:{{name}} - ',
+ stateLabel: '狀態:{{state}}',
+ test: '測試',
+ delete: '刪除',
+ save: '儲存',
+ add: '新增',
+ cancel: '取消',
+ failedToStartScan: '無法開始掃描',
+ nameRequired: '名稱為必填項',
+ entityRequired: 'Home Assistant插座需要實體',
+ mqttTopicRequired: '必須為功率、能源或狀態監控設定至少一個MQTT主題',
+ loadingEntities: '正在載入實體...',
+ loading: '載入中...',
+ failedToLoadEntities: '載入實體失敗:{{error}}',
+ noEntitiesMatching: '未找到匹配"{{search}}"的實體',
+ noEntitiesAvailable: '無可用實體',
+ searchingEntities: '搜尋所有實體(找到{{count}}個)',
+ showingEntities: '顯示 switch、light、input_boolean({{count}}個可用)',
+ energyMonitoringOptional: '能源監控(可選)',
+ energyMonitoringHint: '搜尋並選擇提供功率/能源資料的感測器。',
+ powerSensorW: '功率感測器(W)',
+ energyTodayKwh: '今日能源(kWh)',
+ totalEnergyKwh: '總能源(kWh)',
+ noMatchingSensors: '無匹配的感測器',
+ none: '無',
+ mqttNotConfigured: 'MQTT代理未設定。請在以下位置設定代理地址',
+ mqttSettingsPath: '設定 → 網路 → MQTT發布',
+ mqttNotConfiguredSuffix: '(您不需要啟用發布,只需填寫代理詳細資訊)。',
+ mqttMonitorOnlyDescription: 'MQTT插座透過MQTT訂閱接收功率/能源資料。開關控制不可用 - 請使用您的MQTT代理或家庭自動化系統。',
+ powerMonitoring: '功率監控',
+ energyMonitoring: '能源監控',
+ stateMonitoring: '狀態監控',
+ optional: '可選',
+ topic: '主題',
+ jsonPath: 'JSON路徑',
+ multiplier: '乘數',
+ onValue: 'ON值',
+ mqttPowerHint: 'JSON路徑從JSON負載中提取值(例如"power_l1")。如果主題發布原始數值,請留空。\n乘數:mW→W使用0.001,kW→W使用1000。',
+ mqttEnergyHint: 'JSON路徑從JSON負載中提取值。原始值請留空。\n乘數:Wh→kWh使用0.001,MWh→kWh使用1000。',
+ mqttStateHint: 'JSON路徑從JSON負載中提取值。原始值請留空。\nON值:表示"ON"的確切字串。留空以自動檢測(ON、true、1)。',
+ // REST smart plug
+ restControl: '控制',
+ restOnUrl: '開啟 URL',
+ restOffUrl: '關閉 URL',
+ restOnBody: '開啟請求內容',
+ restOffBody: '關閉請求內容',
+ restMethod: 'HTTP 方法',
+ restHeaders: '自訂標頭(JSON)',
+ restStatusUrl: '狀態 URL',
+ restStatusPath: '狀態 JSON 路徑',
+ restStatusOnValue: 'ON 值',
+ restPowerUrl: '功率URL',
+ restPowerPath: '功率 JSON 路徑',
+ restPowerMultiplier: '功率乘數',
+ restEnergyUrl: '能耗URL',
+ restEnergyPath: '能耗 JSON 路徑',
+ restEnergyMultiplier: '能耗乘數',
+ restUrlRequired: 'REST 插座至少需要一個 URL(ON 或 OFF)',
+ restHeadersHint: '例如:{"Authorization": "Bearer your-token"}',
+ restBodyHint: '例如:ON、{"state": "on"}',
+ restStatusHint: '用於輪詢目前狀態的 URL',
+ restPathHint: '例如:state 或 data.power.status',
+ restPowerUrlHint: '功率資料的獨立URL(留空則使用狀態URL)',
+ restEnergyUrlHint: '能耗資料的獨立URL(留空則使用狀態URL)',
+ restEnergyHint: '每個值可以使用獨立的URL,或回退到狀態 URL。使用乘數進行單位轉換(例如:0.001 將 Wh 轉換為 kWh)。',
+ testConnection: '測試連線',
+ connectionSuccess: '連線成功',
+ noSwitchesInSwitchbar: '開關欄中沒有開關',
+ enableSwitchbarHint: '在設定 > 智慧插座中啟用"在開關欄顯示"',
+ },
+
+ // Notifications
+ notifications: {
+ // Provider types
+ providerTypes: {
+ callmebot: 'CallMeBot/WhatsApp',
+ ntfy: 'ntfy',
+ pushover: 'Pushover',
+ telegram: 'Telegram',
+ email: '電子郵件',
+ discord: 'Discord',
+ webhook: 'Webhook',
+ homeassistant: 'Home Assistant',
+ },
+ // Provider descriptions
+ providerDescriptions: {
+ email: 'SMTP 電子郵件通知',
+ telegram: '透過 Telegram 機器人傳送通知',
+ discord: '透過 Webhook 傳送到 Discord 頻道',
+ ntfy: '免費、可自託管的推送通知',
+ pushover: '簡單、可靠的推送通知',
+ callmebot: '透過 CallMeBot 免費傳送 WhatsApp 通知',
+ webhook: '通用 HTTP POST 到任意 URL',
+ homeassistant: 'Home Assistant 儀表板中的持久通知',
+ },
+ // NotificationProviderCard
+ lastSuccess: '上次:{{date}}',
+ error: '錯誤',
+ printer: '印表機:',
+ allPrinters: '所有印表機',
+ sendTestNotification: '傳送測試通知',
+ eventSettings: '事件設定',
+ enabled: '已啟用',
+ sendFromProvider: '從此提供者傳送通知',
+ // Event categories
+ printEvents: '列印事件',
+ printerStatus: '印表機狀態',
+ amsAlarms: 'AMS 警報',
+ amsHtAlarms: 'AMS-HT 警報',
+ printQueue: '列印佇列',
+ // Event tags (badges)
+ start: '開始',
+ plateCheck: '熱床檢測',
+ complete: '完成',
+ failed: '失敗',
+ stopped: '已停止',
+ progress: '進度',
+ offline: '離線',
+ lowFilament: '耗材不足',
+ maintenance: '維護',
+ amsHumidity: 'AMS 濕度',
+ amsTemp: 'AMS 溫度',
+ amsHtHumidity: 'AMS-HT 濕度',
+ amsHtTemp: 'AMS-HT 溫度',
+ bedCooled: '熱床已冷卻',
+ firstLayer: '首層完成',
+ quiet: '免打擾',
+ digest: '摘要 {{time}}',
+ // Event labels (expanded settings)
+ printStarted: '列印已開始',
+ plateNotEmpty: '熱床非空',
+ plateNotEmptyDescription: '列印前偵測到物體',
+ printCompleted: '列印已完成',
+ bedCooledLabel: '熱床已冷卻',
+ bedCooledDescription: '列印後熱床溫度降至閾值以下',
+ firstLayerCompleteLabel: '首層列印完成',
+ firstLayerCompleteDescription: '首層完成時傳送帶照片的通知',
+ missingSpoolAssignmentLabel: '缺少料卷分配',
+ missingSpoolAssignmentDescription: '當列印開始且所需料盤沒有分配料卷時傳送通知',
+ printFailed: '列印失敗',
+ printStopped: '列印已停止',
+ progressMilestones: '進度里程碑',
+ progressMilestonesDescription: '在 25%、50%、75% 時通知',
+ printerOffline: '印表機離線',
+ printerError: '印表機錯誤',
+ lowFilamentLabel: '耗材不足',
+ maintenanceDue: '需要維護',
+ maintenanceDueDescription: '需要維護時通知',
+ amsHumidityHigh: 'AMS 濕度過高',
+ amsHumidityHighDescription: '普通 AMS 濕度超過閾值',
+ amsTemperatureHigh: 'AMS 溫度過高',
+ amsTemperatureHighDescription: '普通 AMS 溫度超過閾值',
+ amsHtHumidityHigh: 'AMS-HT 濕度過高',
+ amsHtHumidityHighDescription: 'AMS-HT 濕度超過閾值',
+ amsHtTemperatureHigh: 'AMS-HT 溫度過高',
+ amsHtTemperatureHighDescription: 'AMS-HT 溫度超過閾值',
+ // Queue events
+ jobAdded: '任務已新增',
+ jobAddedDescription: '任務已新增到佇列',
+ jobAssigned: '任務已分配',
+ jobAssignedDescription: '基於模型的任務已分配給印表機',
+ jobStarted: '任務已開始',
+ jobStartedDescription: '佇列任務已開始列印',
+ jobWaiting: '任務等待中',
+ jobWaitingDescription: '任務正在等待耗材或印表機',
+ jobSkipped: '任務已跳過',
+ jobSkippedDescription: '任務已跳過(上一個失敗)',
+ jobFailed: '任務失敗',
+ jobFailedDescription: '任務啟動失敗',
+ queueComplete: '佇列已完成',
+ queueCompleteDescription: '所有佇列任務已完成',
+ // Quiet hours
+ quietHours: '免打擾時段',
+ noNotificationsDuring: '在此時段內不傳送通知',
+ editProviderToChangeQuietHours: '編輯提供者以更改免打擾時段',
+ // Daily digest
+ dailyDigest: '每日摘要',
+ batchNotifications: '將通知彙總為每日摘要',
+ sendAt: '傳送於 {{time}}',
+ editProviderToChangeDigestTime: '編輯提供者以更改摘要時間',
+ // Actions
+ edit: '編輯',
+ deleteProvider: '刪除通知提供者',
+ deleteConfirm: '確定要刪除"{{name}}"嗎?此操作無法復原。',
+ delete: '刪除',
+ // AddNotificationModal
+ addTitle: '新增通知提供者',
+ editTitle: '編輯通知提供者',
+ nameLabel: '名稱 *',
+ namePlaceholder: '我的通知',
+ providerTypeLabel: '提供者類型 *',
+ configuration: '設定',
+ testConfiguration: '測試設定',
+ printerFilter: '印表機篩選',
+ onlyFromPrinter: '僅傳送來自此印表機的事件通知',
+ quietHoursDnd: '免打擾時段',
+ quietStart: '開始',
+ quietEnd: '結束',
+ dailyDigestLabel: '每日摘要',
+ sendDigestAt: '傳送摘要於',
+ digestCollected: '事件將被收集並在此時間作為單條摘要傳送',
+ notificationEvents: '通知事件',
+ progressPercent: '(25%、50%、75%)',
+ bedCooledAfterPrint: '(列印完成後)',
+ cancel: '取消',
+ save: '儲存',
+ add: '新增',
+ nameRequired: '名稱為必填項',
+ fieldRequired: '{{field}}為必填項',
+ // Config field labels
+ phoneNumber: '電話號碼',
+ apiKey: 'API 金鑰',
+ serverUrl: '伺服器 URL',
+ topic: '主題',
+ authToken: '認證權杖',
+ userKey: '使用者金鑰',
+ appToken: '應用程式權杖',
+ priority: '優先順序',
+ botToken: '機器人權杖',
+ chatId: '聊天 ID',
+ smtpServer: 'SMTP 伺服器',
+ smtpPort: 'SMTP 連接埠',
+ security: '安全',
+ authentication: '認證',
+ username: '使用者名稱',
+ password: '密碼',
+ fromEmail: '寄件人信箱',
+ toEmail: '收件人信箱',
+ webhookUrl: 'Webhook URL',
+ payloadFormat: '負載格式',
+ authorization: '授權',
+ titleFieldName: '標題欄位名',
+ messageFieldName: '訊息欄位名',
+ // NotificationTemplateEditor
+ editTemplate: '編輯範本:{{name}}',
+ titleLabel: '標題',
+ bodyLabel: '正文',
+ titlePlaceholder: '通知標題...',
+ bodyPlaceholder: '通知正文...',
+ availableVariables: '可用變數',
+ clickToInsert: '點選插入到正文游標位置',
+ livePreview: '即時預覽',
+ hide: '隱藏',
+ show: '顯示',
+ loadingPreview: '載入預覽中...',
+ enterTemplateContent: '輸入範本內容以檢視預覽',
+ titlePreview: '標題:',
+ bodyPreview: '正文:',
+ resetToDefault: '恢復預設',
+ titleRequired: '標題為必填項',
+ bodyRequired: '正文為必填項',
+ // NotificationLogViewer
+ notificationLog: '通知日誌',
+ showFailedOnly: '僅顯示失敗',
+ last24Hours: '最近 24 小時',
+ last7Days: '最近 7 天',
+ last30Days: '最近 30 天',
+ last90Days: '最近 90 天',
+ justNow: '剛剛',
+ noFailedNotifications: '沒有失敗的通知',
+ noNotificationsLogged: '沒有通知紀錄',
+ unknownProvider: '未知提供者',
+ logTitle: '標題',
+ logMessage: '訊息',
+ logError: '錯誤',
+ logProvider: '提供者:{{type}}',
+ logTime: '時間:{{time}}',
+ refresh: '重新整理',
+ clearOld: '清除舊紀錄',
+ statsSummary: '最近 {{days}} 天:',
+ statsNotifications: '條通知',
+ statsSent: '{{count}} 條已傳送',
+ statsFailed: '{{count}} 條失敗',
+ // Event type labels (for log viewer)
+ eventTypes: {
+ print_start: '列印已開始',
+ print_complete: '列印完成',
+ print_failed: '列印失敗',
+ print_stopped: '列印已停止',
+ print_progress: '進度',
+ printer_offline: '印表機離線',
+ printer_error: '印表機錯誤',
+ filament_low: '耗材不足',
+ maintenance_due: '需要維護',
+ test: '測試',
+ },
+ userEmail: {
+ title: '通知',
+ emailNotifications: '郵件通知',
+ emailNotificationsDesc: '接收您自己列印任務的郵件通知。郵件將透過進階身份驗證中設定的 SMTP 設定傳送。',
+ sendingTo: '通知將傳送至',
+ noEmailWarning: '您的帳戶沒有郵件地址。請聯絡管理員新增。',
+ printJobNotifications: '列印任務通知',
+ printJobNotificationsDesc: '選擇哪些事件會觸發您提交的列印任務的郵件通知。',
+ printJobStarts: '列印任務開始',
+ printJobStartsDesc: '當您的列印任務開始時收到通知。',
+ printJobFinishes: '列印任務完成',
+ printJobFinishesDesc: '當您的列印任務成功完成時收到通知。',
+ printErrors: '列印錯誤',
+ printErrorsDesc: '當您的列印任務失敗或遇到錯誤時收到通知。',
+ printJobStops: '列印任務停止',
+ printJobStopsDesc: '當您的列印任務被取消或停止時收到通知。',
+ saveSuccess: '通知偏好設定已儲存。',
+ saveError: '儲存通知偏好設定失敗。',
+ },
+ },
+
+ // Rich Text Editor
+ richTextEditor: {
+ bold: '粗體',
+ italic: '斜體',
+ underline: '底線',
+ bulletList: '無序列表',
+ numberedList: '有序列表',
+ alignLeft: '左對齊',
+ alignCenter: '居中對齊',
+ alignRight: '右對齊',
+ addLink: '新增連結',
+ removeLink: '移除連結',
+ },
+
+ // External Links
+ externalLinks: {
+ noLinksConfigured: '未設定外部連結',
+ deleteLink: '刪除連結',
+ removeCustomIcon: '移除自訂圖示',
+ openInNewTab: '在新標籤頁中開啟',
+ placeholders: {
+ linkName: '我的連結',
+ },
+ },
+
+ // Keyboard Shortcuts Modal
+ keyboardShortcuts: {
+ title: '鍵盤快捷鍵',
+ navigation: '導航',
+ archivesSection: '歸檔',
+ kProfilesSection: 'K 值設定',
+ generalSection: '通用',
+ shortcuts: {
+ goToPrinters: '前往印表機',
+ goToArchives: '前往歸檔',
+ goToQueue: '前往佇列',
+ goToStats: '前往統計',
+ goToProfiles: '前往雲端設定',
+ goToSettings: '前往設定',
+ focusSearch: '聚焦搜尋',
+ openUploadModal: '開啟上傳對話方塊',
+ clearSelection: '清除選擇 / 取消焦點',
+ contextMenu: '卡片右鍵選單',
+ refreshProfiles: '重新整理設定',
+ newProfile: '新增設定',
+ exitSelectionMode: '結束選擇模式',
+ showHelp: '顯示此協助',
+ },
+ footer: '按 Esc 或點選外部關閉',
+ },
+
+ // Notification Log
+ notificationLog: {
+ title: '通知日誌',
+ events: {
+ printStarted: '列印開始',
+ printComplete: '列印完成',
+ printFailed: '列印失敗',
+ printStopped: '列印停止',
+ progress: '進度',
+ printerOffline: '印表機離線',
+ printerError: '印表機錯誤',
+ lowFilament: '耗材不足',
+ maintenanceDue: '維護到期',
+ test: '測試',
+ },
+ timeAgo: {
+ justNow: '剛剛',
+ minutesAgo: '{{minutes}} 分鐘前',
+ hoursAgo: '{{hours}} 小時前',
+ },
+ },
+
+ // Restore/Backup Modal
+ restoreBackup: {
+ title: '恢復備份',
+ restoring: '恢復中...',
+ restoreComplete: '恢復完成',
+ restoreFailed: '恢復失敗',
+ importSettings: '從備份檔案匯入設定',
+ pleaseWait: '請稍候,正在恢復您的資料',
+ clickToSelect: '點選選擇備份檔案(.json 或 .zip)',
+ howDuplicateHandling: '重複處理方式:',
+ categories: {
+ printers: '印表機',
+ smartPlugs: '智慧插座',
+ notificationProviders: '通知提供者',
+ filaments: '耗材',
+ archives: '歸檔',
+ pendingUploads: '待處理上傳',
+ settingsTemplates: '設定和範本',
+ },
+ matchingInfo: {
+ printers: '按序列號匹配',
+ smartPlugs: '按 IP 位址匹配',
+ notificationProviders: '按名稱匹配',
+ filaments: '按名稱 + 類型 + 品牌匹配',
+ archives: '按內容雜湊匹配',
+ pendingUploads: '按檔名匹配',
+ settingsTemplates: '始終覆蓋',
+ },
+ replaceExisting: '替換現有資料',
+ keepExisting: '保留現有資料',
+ replaceDescription: '用備份資料覆蓋已存在的項目',
+ keepDescription: '僅恢復不存在的項目',
+ caution: '注意:',
+ cautionText: '覆蓋將用備份資料替換您目前的設定。出於安全考慮,印表機存取碼永遠不會被覆蓋。',
+ itemsRestored: '已恢復項目',
+ itemsSkipped: '已跳過項目',
+ restored: '已恢復',
+ skipped: '已跳過(已存在)',
+ filesLabel: '檔案(3MF、縮圖等)',
+ newApiKeysGenerated: '已產生新 API 金鑰',
+ newApiKeysWarning: '這些金鑰僅顯示一次。請立即複製!',
+ processingBackup: '處理備份檔案中...',
+ noDataFound: '備份檔案中未找到可恢復的資料。',
+ failedToRestore: '恢復備份失敗。請檢查檔案格式。',
+ },
+
+ // Backup Export Modal
+ backupExport: {
+ title: '匯出備份',
+ selectData: '選擇要包含的資料',
+ selectAll: '全選',
+ selectNone: '全不選',
+ categoryDescriptions: {
+ settings: '語言、主題、更新偏好',
+ notifications: 'ntfy、Pushover、Discord 等',
+ templates: '自訂訊息範本',
+ smartPlugs: 'Tasmota 插座設定',
+ externalLinks: '側邊欄外部服務連結',
+ printers: '印表機資訊(不含存取碼)',
+ plateDetection: '空列印板參考影像',
+ filaments: '耗材類型和成本',
+ maintenance: '自訂維護計畫',
+ archives: '所有列印資料 + 檔案(3MF、縮圖、照片)',
+ projects: '專案、材料清單和附件',
+ pendingUploads: '虛擬印表機待審核的上傳',
+ apiKeys: 'Webhook API 金鑰(匯入時產生新金鑰)',
+ },
+ requiresPrinters: '需要選擇印表機',
+ zipFileWarning: '將建立 ZIP 檔案。',
+ zipFileDescription: '包括所有 3MF 檔案、縮圖、縮時攝影和照片。這可能需要一些時間並產生較大的檔案。',
+ includeAccessCodes: '包含存取碼',
+ includeAccessCodesDescription: '用於轉移到另一臺機器',
+ includeAccessCodesWarning: '存取碼將以明文形式包含。請妥善保管此備份檔案!',
+ categoriesSelected: '已選擇 {{selectedCount}} 個類別',
+ },
+
+ // Pending Uploads Panel
+ pendingUploads: {
+ placeholders: {
+ notes: '新增關於此列印的備註...',
+ },
+ discardUpload: '丟棄上傳',
+ archiveAllUploads: '歸檔所有上傳',
+ discardAllUploads: '丟棄所有上傳',
+ archive: '歸檔',
+ timeAgo: {
+ justNow: '剛剛',
+ minutesAgo: '{{minutes}} 分鐘前',
+ hoursAgo: '{{hours}} 小時前',
+ daysAgo: '{{days}} 天前',
+ },
+ },
+
+ // API Browser
+ apiBrowser: {
+ placeholders: {
+ requestBody: 'JSON 請求體...',
+ searchEndpoints: '搜尋端點...',
+ },
+ },
+
+ // Configure AMS Slot Modal
+ configureAmsSlot: {
+ title: '設定 AMS 槽位',
+ slotConfigured: '槽位已設定!',
+ configuringSlot: '正在設定槽位:',
+ slotLabel: '{{ams}} 槽位 {{slot}}',
+ searchPresets: '搜尋預設...',
+ colorPlaceholder: '顏色名稱或十六進位(例如:棕色、FF8800)',
+ clearCustomColor: '清除自訂顏色',
+ noCloudPresets: '無雲端預設。登入拓竹雲以同步。',
+ noPresetsAvailable: '無可用預設。登入拓竹雲或匯入本機設定。',
+ noMatchingPresets: '未找到匹配的預設。',
+ custom: '自訂',
+ builtin: '內建',
+ settingsSentToPrinter: '設定已傳送到印表機',
+ filamentProfile: '耗材設定',
+ kProfileLabel: 'K 值設定(壓力推進)',
+ filteringFor: '篩選:{{material}}',
+ noKProfile: '無 K 值設定(使用預設值 0.020)',
+ noMatchingKProfiles: '未找到匹配的 K 值設定。將使用預設 K=0.020。',
+ selectFilamentFirst: '請先選擇耗材設定',
+ kFromCalibration: 'K={{value}}(來自印表機校準)',
+ customColorLabel: '自訂顏色(可選)',
+ presetColors: '{{name}} 顏色:',
+ showLessColors: '顯示更少顏色',
+ showMoreColors: '顯示更多顏色',
+ clear: '清除',
+ hexLabel: '十六進位:#{{hex}}',
+ resetting: '重設中...',
+ resetSlot: '重設槽位',
+ cancel: '取消',
+ configuring: '設定中...',
+ configureSlot: '設定槽位',
+ },
+
+ // GitHub Backup Settings
+ githubBackup: {
+ title: 'GitHub 備份',
+ history: '歷史',
+ downloadBackup: '下載備份',
+ restoreBackup: '恢復備份',
+ noBackupsYet: '尚無備份',
+ },
+
+ // Email Settings
+ emailSettings: {
+ placeholders: {
+ fromName: 'BamBuddy',
+ },
+ },
+
+ // Tag Management Modal
+ tagManagement: {
+ searchTags: '搜尋標籤...',
+ renameTag: '重新命名標籤',
+ deleteTag: '刪除標籤',
+ },
+
+ // Notification Template Editor
+ notificationTemplates: {
+ placeholders: {
+ title: '通知標題...',
+ body: '通知正文...',
+ },
+ },
+
+ // Batch Tag Modal
+ batchTag: {
+ placeholders: {
+ newTag: '輸入新標籤...',
+ },
+ },
+
+ // Photo Gallery Modal
+ photoGallery: {
+ deletePhoto: '刪除照片',
+ },
+
+ // Filament Hover Card
+ filamentHoverCard: {
+ copySpoolUuid: '複製耗材 UUID',
+ },
+
+ // K Profiles View
+ kProfilesView: {
+ hasNote: '有備註',
+ copyProfile: '複製設定',
+ },
+
+ // Layout/Navigation
+ layout: {
+ openMenu: '開啟選單',
+ noPermissionSystemInfo: '您沒有檢視系統資訊的權限',
+ },
+
+ // Dashboard
+ dashboard: {
+ dragToReorder: '拖曳以重新排列',
+ hideWidget: '隱藏小工具',
+ },
+
+ // Notification Provider Card
+ notificationProviderCard: {
+ deleteNotificationProvider: '刪除通知提供者',
+ },
+
+ // File Manager Modal
+ fileManagerModal: {
+ closeFileManager: '關閉檔案管理器',
+ sortFiles: '排序檔案',
+ goToParentFolder: '返回上級資料夾',
+ threeView: '3D 檢視',
+ },
+
+ // Embedded Camera Viewer
+ embeddedCameraViewer: {
+ refreshStream: '重新整理流',
+ close: '關閉',
+ zoomOut: '縮小',
+ resetZoom: '重設縮放',
+ zoomIn: '放大',
+ dragToResize: '拖曳調整大小',
+ },
+
+ // Timelapse Viewer
+ timelapseViewer: {
+ skipBack5s: '後退 5 秒',
+ skipForward5s: '前進 5 秒',
+ },
+
+ // Notification Providers
+ notificationProviders: {
+ descriptions: {
+ email: 'SMTP 郵件通知',
+ telegram: '透過 Telegram 機器人通知',
+ discord: '透過 Webhook 傳送到 Discord 頻道',
+ ntfy: '免費、可自託管的推送通知',
+ pushover: '簡單、可靠的推送通知',
+ callmebot: '透過 CallMeBot 的免費 WhatsApp 通知',
+ webhook: '通用 HTTP POST 到任意 URL',
+ },
+ },
+
+ // Log Viewer
+ logViewer: {
+ searchPlaceholder: '搜尋訊息或日誌名稱...',
+ noLogEntries: '未找到日誌條目',
+ },
+
+ // Switchbar Popover
+ switchbarPopover: {
+ noSwitchesInSwitchbar: '切換欄中沒有開關',
+ },
+
+ // Project Page Modal
+ projectPageModal: {
+ placeholders: {
+ title: '標題',
+ designer: '設計師',
+ license: '許可證',
+ description: '輸入描述...',
+ profileTitle: '設定標題',
+ profileDescription: '設定描述...',
+ },
+ },
+
+ // Spoolman Settings
+ spoolmanSettings: {},
+
+ // Time
+ time: {
+ unknown: '-',
+ waiting: '等待中',
+ justNow: '剛剛',
+ now: '現在',
+ minsAgo: '{{count}} 分鐘前',
+ inMins: '{{count}} 分鐘後',
+ hoursAgo: '{{count}} 小時前',
+ inHours: '{{count}} 小時後',
+ daysAgo: '{{count}} 天前',
+ inDays: '{{count}} 天後',
+ },
+
+ // SpoolBuddy Kiosk
+ spoolbuddy: {
+ nav: {
+ dashboard: '儀表板',
+ ams: 'AMS',
+ inventory: '庫存',
+ writeTag: '寫入',
+ settings: '設定',
+ },
+ status: {
+ nfcReady: 'NFC 就緒',
+ nfcOff: 'NFC 關閉',
+ offline: '離線',
+ online: '線上',
+ noPrinters: '無印表機',
+ deviceOffline: '裝置離線',
+ waitingConnection: '等待裝置連線...',
+ systemReady: '系統就緒',
+ status: '狀態',
+ },
+ dashboard: {
+ readyToScan: '準備掃描',
+ idleMessage: '將耗材放在磅秤上以識別',
+ nfcHint: 'NFC 標籤將自動讀取',
+ device: '裝置',
+ syncWeight: '同步重量',
+ weightSynced: '已同步!',
+ unknownTag: '未知標籤',
+ newTag: '偵測到新標籤',
+ onScale: '在磅秤上',
+ linkSpool: '連結到耗材',
+ linkTagTitle: '將標籤連結到耗材',
+ linkTag: '連結標籤',
+ selectSpool: '選擇要連結此標籤的耗材:',
+ noUntagged: '未找到沒有標籤的耗材',
+ tagDetected: '偵測到標籤',
+ noTag: '無標籤',
+ tagId: '標籤',
+ grossWeight: '毛重',
+ spoolSize: '耗材盤尺寸',
+ close: '關閉',
+ currentSpool: '目前耗材',
+ },
+ modal: {
+ spoolDetected: '偵測到耗材',
+ assignToAms: '分配到 AMS',
+ syncWeight: '同步重量',
+ weightSynced: '已同步!',
+ syncing: '同步中...',
+ newTagDetected: '偵測到新標籤',
+ addToInventory: '新增到庫存',
+ assignToAmsTitle: '分配到 AMS',
+ selectSlot: '選擇槽位',
+ assign: '分配',
+ assigning: '分配中...',
+ assignSuccess: '已分配!',
+ assignError: '分配耗材失敗。請重試。',
+ noPrinterSelected: '選擇印表機...',
+ noAmsDetected: '此印表機未偵測到 AMS',
+ slot: '槽位',
+ },
+ weight: {
+ noReading: '無讀數',
+ stable: '穩定',
+ measuring: '測量中...',
+ tare: '去皮',
+ calibrate: '校準',
+ },
+ spool: {
+ remaining: '剩餘',
+ material: '材料',
+ brand: '品牌',
+ color: '顏色',
+ coreWeight: '軸心重',
+ labelWeight: '標籤重',
+ scaleWeight: '磅秤重',
+ netWeight: '淨重',
+ lastUsed: '上次使用',
+ },
+ ams: {
+ noData: '未偵測到 AMS',
+ connectAms: '連線 AMS 以檢視耗材槽位',
+ noPrinter: '未選擇印表機',
+ selectPrinter: '從頂部欄選擇印表機',
+ printerDisconnected: '印表機已斷開',
+ humidity: '濕度',
+ level: '餘量',
+ active: '活躍',
+ slot: '槽位',
+ empty: '空',
+ },
+ inventory: {
+ search: '搜尋耗材...',
+ empty: '庫存中沒有耗材',
+ noResults: '沒有匹配的耗材',
+ spools: '個耗材',
+ addSpool: '新增耗材',
+ },
+ settings: {
+ // Tabs
+ tabDevice: '裝置',
+ tabDisplay: '顯示',
+ tabScale: '磅秤',
+ tabUpdates: '更新',
+ // Device tab
+ nfcReader: 'NFC 讀卡器',
+ type: '類型',
+ connection: '連線',
+ notConnected: '不適用',
+ deviceInfo: '裝置資訊',
+ hostname: '主機',
+ uptime: '執行時間',
+ systemConfig: '後端與認證',
+ backendUrl: 'Bambuddy 後端 URL',
+ apiToken: 'API 權杖',
+ apiTokenPlaceholder: '輸入 API 權杖',
+ saveConfig: '儲存設定',
+ systemQueued: '設定已加入佇列。',
+ nfcDiagnostic: 'NFC 診斷',
+ scaleDiagnostic: '磅秤診斷',
+ readTagDiagnostic: '讀取標籤診斷',
+ testNfc: '測試讀卡器',
+ testScale: '測試精度',
+ testReadTag: '讀取標籤',
+ systemFieldsRequired: '後端 URL 為必填項。',
+ // Display tab
+ brightness: '亮度',
+ saved: '已儲存',
+ noBacklight: '未偵測到 DSI 背光。亮度控制需要 DSI 螢幕。',
+ screenBlank: '螢幕熄滅超時',
+ screenBlankDesc: '不活動後螢幕關閉。觸控喚醒。',
+ displayNote: '亮度作為軟體濾鏡套用。',
+ // Scale tab
+ scaleCalibration: '磅秤校準',
+ currentWeight: '目前重量',
+ tareOffset: '去皮',
+ calFactor: '係數',
+ knownWeight: '已知重量',
+ calStep1: '移除磅秤上所有物品並按設定零點。',
+ calStep2: '將已知重量放在磅秤上。',
+ setZero: '設定零點',
+ calibrateNow: '校準',
+ calibrated: '已校準',
+ tareSet: '去皮命令已傳送。等待裝置回應...',
+ tareFailed: '傳送去皮命令失敗',
+ zeroSet: '零點已設定。將已知重量放在磅秤上。',
+ calibrationDone: '校準完成!',
+ calibrationFailed: '校準失敗',
+ lastCalibrated: '上次校準',
+ stable: '穩定',
+ settling: '穩定中...',
+ firmware: '韌體',
+ scale: '磅秤',
+ noDevice: '未找到 SpoolBuddy 裝置',
+ // Updates tab
+ daemonVersion: '守護程式版本',
+ currentVersion: '目前',
+ versionPending: '等待守護程式...',
+ checking: '檢查中...',
+ checkUpdates: '檢查更新',
+ updateAvailable: '有可用更新',
+ updateInstructions: '透過 SSH 更新:執行 SpoolBuddy 安裝腳本進行升級。',
+ upToDate: '已是最新',
+ includeBeta: '包含測試版本',
+ },
+ writeTag: {
+ tabExisting: '現有耗材',
+ tabNew: '新耗材',
+ tabReplace: '替換標籤',
+ searchPlaceholder: '按材料、顏色、品牌搜尋...',
+ noUntaggedSpools: '沒有無標籤的耗材',
+ noTaggedSpools: '沒有有標籤的耗材',
+ selectSpool: '選擇一個耗材,然後將空白 NTAG 放在讀卡器上',
+ placeTag: '將 NTAG 放在讀卡器上',
+ tagReady: '偵測到標籤 — 準備寫入',
+ writeTag: '寫入標籤',
+ replaceTag: '替換標籤',
+ writing: '寫入標籤中...',
+ waiting: '等待 SpoolBuddy...',
+ writeSuccess: '標籤寫入成功!',
+ writeFailed: '寫入失敗',
+ queueFailed: '佇列寫入命令失敗',
+ tryAgain: '重試',
+ cancel: '取消',
+ replaceWarning: '舊標籤將被取消連結。新標籤將替換它。',
+ deviceOffline: 'SpoolBuddy 離線',
+ material: '材料',
+ colorName: '顏色名稱',
+ color: '顏色',
+ brand: '品牌',
+ weight: '重量 (g)',
+ createSpool: '建立耗材',
+ creating: '建立中...',
+ spoolCreated: '耗材已建立!準備寫入。',
+ createFailed: '建立耗材失敗',
+ },
+ quickMenu: {
+ printerPower: '印表機電源',
+ systemControls: '系統',
+ restartDaemon: '重新啟動守護程式',
+ restartBrowser: '重新啟動瀏覽器',
+ reboot: '重新開機',
+ shutdown: '關機',
+ swipeToClose: '向下滑動關閉',
+ confirmTitle: '確認',
+ confirmShutdown: '確定要關閉 SpoolBuddy 嗎?您需要實體存取才能重新開啟。',
+ confirmReboot: '確定要重新開機 SpoolBuddy 嗎?',
+ confirmRestartDaemon: '重新啟動 SpoolBuddy 守護程式?NFC 和磅秤將暫時不可用。',
+ confirmRestartBrowser: '重新啟動kiosk瀏覽器?螢幕將短暫變黑。',
+ confirm: '確認',
+ confirmPlugOn: '開啟 {{name}}?',
+ confirmPlugOff: '關閉 {{name}}?',
+ turnOn: '開啟',
+ turnOff: '關閉',
+ },
+ },
+
+ bugReport: {
+ title: '報告錯誤',
+ description: '描述',
+ descriptionPlaceholder: '出了什麼問題?請描述問題...',
+ email: '信箱(可選)',
+ emailPlaceholder: 'your@email.com',
+ emailPrivacy: '如果提供,您的信箱將包含在GitHub Issue的摺疊部分中,以便維護者後續跟進。',
+ screenshot: '截圖',
+ uploadOrPaste: '上傳、貼上或拖曳圖片',
+ dataCollectedSummary: '報告中包含哪些資料?',
+ dataIncluded: '包含:',
+ dataIncludedList: '應用程式版本、作業系統、架構、Python版本、資料庫統計(僅計數)、印表機型號、噴嘴數量、韌體版本、連線狀態、整合狀態(Spoolman、MQTT、HA)、非敏感設定、網路介面數量、Docker詳情、依賴版本。',
+ dataNeverIncluded: '絕不包含:',
+ dataNeverIncludedList: '印表機名稱、序列號、存取碼、密碼、IP 位址、信箱地址、API金鑰、權杖、Webhook URL、主機名稱或使用者名稱。',
+ submit: '提交',
+ startLogging: '開始偵錯日誌',
+ stepEnableLogging: '偵錯日誌已啟用',
+ stepReproduce: '請現在重現問題',
+ stepStopLogging: '停止並提交報告',
+ stopAndSubmit: '停止並提交',
+ maxDuration: '{{minutes}} 分鐘後自動停止',
+ stoppingLogs: '正在收集日誌並提交...',
+ submitting: '正在提交錯誤報告...',
+ submitSuccess: '錯誤報告提交成功!',
+ submitFailed: '提交錯誤報告失敗',
+ thankYou: '謝謝!',
+ submitted: '您的錯誤報告已提交。',
+ viewIssue: '檢視 Issue',
+ unexpectedError: '發生了意外錯誤',
+ },
+ failureDetection: {
+ title: 'AI 故障檢測',
+ description: '透過自託管的 Obico ML API 監控列印,並對偵測到的故障自動採取行動。',
+ mlUrl: 'Obico ML API 地址',
+ mlUrlHint: '您自託管的 Obico ml_api 容器的基礎 URL(例如 http://192.168.1.10:3333)。',
+ test: '測試',
+ testSuccess: 'ML API 可存取且正常。',
+ testFailed: '無法存取 ML API。',
+ sensitivity: '靈敏度',
+ sensitivityLow: '低(減少誤報)',
+ sensitivityMedium: '中(平衡)',
+ sensitivityHigh: '高(更早檢測,更多誤報)',
+ sensitivityHint: '調整觸發警告和故障的置信度閾值。',
+ action: '偵測到故障時的操作',
+ actionNotify: '僅通知',
+ actionPause: '暫停列印',
+ actionPauseOff: '暫停並切斷電源',
+ pollInterval: '檢查間隔(秒)',
+ pollIntervalHint: '列印過程中每臺印表機的檢查頻率。最小 5 秒,最大 120 秒。',
+ externalUrlMissing: '尚未設定外部 URL。',
+ externalUrlHint: 'ML API 透過 URL 擷取攝影機快照。請在一般設定中設定外部 URL,讓 ML API 容器可以連線到 Bambuddy。',
+ perPrinterTitle: '監控的印表機',
+ perPrinterHint: '選擇檢測服務要監視哪些印表機。',
+ monitorAll: '監控所有已連線的印表機',
+ statusTitle: '狀態',
+ serviceRunning: '服務執行中',
+ thresholds: '低 / 高閾值',
+ activePrinters: '活動列印',
+ noActivePrints: '目前沒有正在進行的列印。',
+ historyTitle: '最近檢測',
+ noHistory: '尚無檢測紀錄。',
+ },
+};