diff --git a/web/src/app/home/components/home-sidebar/HomeSidebar.tsx b/web/src/app/home/components/home-sidebar/HomeSidebar.tsx index 876baf33..fa435cf7 100644 --- a/web/src/app/home/components/home-sidebar/HomeSidebar.tsx +++ b/web/src/app/home/components/home-sidebar/HomeSidebar.tsx @@ -144,6 +144,11 @@ export default function HomeSidebar({ 'https://docs.langbot.app/zh/insight/guide.html', '_blank', ); + } else if (language === 'zh-Hant') { + window.open( + 'https://docs.langbot.app/zh/insight/guide.html', + '_blank', + ); } else { window.open( 'https://docs.langbot.app/en/insight/guide.html', diff --git a/web/src/app/login/page.tsx b/web/src/app/login/page.tsx index d55e3fd3..3a5e22e3 100644 --- a/web/src/app/login/page.tsx +++ b/web/src/app/login/page.tsx @@ -65,6 +65,9 @@ export default function Login() { if (i18n.language === 'zh-CN' || i18n.language === 'zh-Hans') { setCurrentLanguage('zh-Hans'); localStorage.setItem('langbot_language', 'zh-Hans'); + } else if (i18n.language === 'zh-TW' || i18n.language === 'zh-Hant') { + setCurrentLanguage('zh-Hant'); + localStorage.setItem('langbot_language', 'zh-Hant'); } else if (i18n.language === 'ja' || i18n.language === 'ja-JP') { setCurrentLanguage('ja-JP'); localStorage.setItem('langbot_language', 'ja-JP'); @@ -84,6 +87,8 @@ export default function Login() { let lang = 'zh-Hans'; if (language === 'zh-CN') { lang = 'zh-Hans'; + } else if (language === 'zh-TW') { + lang = 'zh-Hant'; } else if (language === 'ja' || language === 'ja-JP') { lang = 'ja-JP'; } else { @@ -164,6 +169,7 @@ export default function Login() { 简体中文 + 繁體中文 English 日本語 diff --git a/web/src/app/register/page.tsx b/web/src/app/register/page.tsx index d885f3b0..56ae7e9c 100644 --- a/web/src/app/register/page.tsx +++ b/web/src/app/register/page.tsx @@ -63,6 +63,9 @@ export default function Register() { if (i18n.language === 'zh-CN' || i18n.language === 'zh-Hans') { setCurrentLanguage('zh-Hans'); localStorage.setItem('langbot_language', 'zh-Hans'); + } else if (i18n.language === 'zh-TW' || i18n.language === 'zh-Hant') { + setCurrentLanguage('zh-Hant'); + localStorage.setItem('langbot_language', 'zh-Hant'); } else if (i18n.language === 'ja' || i18n.language === 'ja-JP') { setCurrentLanguage('ja-JP'); localStorage.setItem('langbot_language', 'ja-JP'); @@ -82,6 +85,8 @@ export default function Register() { let lang = 'zh-Hans'; if (language === 'zh-CN') { lang = 'zh-Hans'; + } else if (language === 'zh-TW') { + lang = 'zh-Hant'; } else if (language === 'ja' || language === 'ja-JP') { lang = 'ja-JP'; } else { @@ -148,6 +153,7 @@ export default function Register() { 简体中文 + 繁體中文 English 日本語 diff --git a/web/src/i18n/index.ts b/web/src/i18n/index.ts index fd8f5c7c..74995e00 100644 --- a/web/src/i18n/index.ts +++ b/web/src/i18n/index.ts @@ -6,6 +6,7 @@ import LanguageDetector from 'i18next-browser-languagedetector'; import enUS from './locales/en-US'; import zhHans from './locales/zh-Hans'; +import zhHant from './locales/zh-Hant'; import jaJP from './locales/ja-JP'; i18n @@ -19,6 +20,9 @@ i18n 'zh-Hans': { translation: zhHans, }, + 'zh-Hant': { + translation: zhHant, + }, 'ja-JP': { translation: jaJP, }, diff --git a/web/src/i18n/locales/zh-Hant.ts b/web/src/i18n/locales/zh-Hant.ts new file mode 100644 index 00000000..e71f0e53 --- /dev/null +++ b/web/src/i18n/locales/zh-Hant.ts @@ -0,0 +1,330 @@ +const zhHant = { + common: { + login: '登入', + logout: '登出', + email: '電子郵件', + password: '密碼', + welcome: '歡迎回到 LangBot 👋', + continueToLogin: '登入以繼續', + loginSuccess: '登入成功', + loginFailed: '登入失敗,請檢查電子郵件和密碼是否正確', + enterEmail: '輸入電子郵件地址', + enterPassword: '輸入密碼', + invalidEmail: '請輸入有效的電子郵件地址', + emptyPassword: '請輸入密碼', + language: '語言', + helpDocs: '輔助說明', + create: '建立', + edit: '編輯', + delete: '刪除', + add: '新增', + select: '請選擇', + cancel: '取消', + submit: '提交', + error: '錯誤', + success: '成功', + save: '儲存', + saving: '儲存中...', + confirm: '確認', + confirmDelete: '確認刪除', + deleteConfirmation: '您確定要刪除這個嗎?', + selectOption: '選擇一個選項', + required: '必填', + enable: '是否啟用', + name: '名稱', + description: '描述', + close: '關閉', + deleteSuccess: '刪除成功', + deleteError: '刪除失敗:', + addRound: '新增回合', + copySuccess: '複製成功', + test: '測試', + forgotPassword: '忘記密碼?', + loading: '載入中...', + }, + notFound: { + title: '頁面不存在', + description: + '您要查詢的頁面似乎不存在。請檢查您輸入的 URL 是否正確,或返回首頁。', + back: '上一級', + home: '返回主頁', + help: '查看說明文件', + }, + models: { + title: '模型設定', + description: '設定和管理可在流程線中使用的模型', + createModel: '建立模型', + editModel: '編輯模型', + getModelListError: '取得模型清單失敗:', + modelName: '模型名稱', + modelProvider: '模型供應商', + modelBaseURL: '基礎 URL', + modelAbilities: '模型能力', + saveSuccess: '儲存成功', + saveError: '儲存失敗:', + createSuccess: '建立成功', + createError: '建立失敗:', + deleteSuccess: '刪除成功', + deleteError: '刪除失敗:', + deleteConfirmation: '您確定要刪除這個模型嗎?', + modelNameRequired: '模型名稱不能為空', + modelProviderRequired: '模型供應商不能為空', + requestURLRequired: '請求URL不能為空', + apiKeyRequired: 'API Key不能為空', + keyNameRequired: '鍵名不能為空', + mustBeValidNumber: '必須是有效的數字', + mustBeTrueOrFalse: '必須是 true 或 false', + requestURL: '請求URL', + apiKey: 'API Key', + abilities: '能力', + selectModelAbilities: '選擇模型能力', + visionAbility: '視覺能力', + functionCallAbility: '函數呼叫', + extraParameters: '額外參數', + addParameter: '新增參數', + keyName: '鍵名', + type: '類型', + value: '值', + string: '字串', + number: '數字', + boolean: '布林值', + selectModelProvider: '選擇模型供應商', + modelProviderDescription: '請填寫供應商向您提供的模型名稱', + selectModel: '請選擇模型', + testSuccess: '測試成功', + testError: '測試失敗,請檢查模型設定', + llmModels: '對話模型', + }, + bots: { + title: '機器人', + description: '建立和管理機器人,這是 LangBot 與各個平台連接的入口', + createBot: '建立機器人', + editBot: '編輯機器人', + getBotListError: '取得機器人清單失敗:', + botName: '機器人名稱', + botDescription: '機器人描述', + botNameRequired: '機器人名稱不能為空', + botDescriptionRequired: '機器人描述不能為空', + adapterRequired: '適配器不能為空', + defaultDescription: '一個機器人', + getBotConfigError: '取得機器人設定失敗:', + saveSuccess: '儲存成功', + saveError: '儲存失敗:', + createSuccess: '建立成功 請啟用或修改綁定流程線', + createError: '建立失敗:', + deleteSuccess: '刪除成功', + deleteError: '刪除失敗:', + deleteConfirmation: '您確定要刪除這個機器人嗎?', + platformAdapter: '平台/適配器選擇', + selectAdapter: '選擇適配器', + adapterConfig: '適配器設定', + bindPipeline: '綁定流程線', + selectPipeline: '選擇流程線', + botLogTitle: '機器人日誌', + enableAutoRefresh: '開啟自動重新整理', + session: '對話', + yesterday: '昨天', + earlier: '更久之前', + dateFormat: '{{month}}月{{day}}日', + setBotEnableError: '設定機器人啟用狀態失敗', + log: '日誌', + configuration: '設定', + logs: '日誌', + }, + plugins: { + title: '外掛管理', + description: '安裝和設定用於擴展 LangBot 功能的外掛', + createPlugin: '建立外掛', + editPlugin: '編輯外掛', + installed: '已安裝', + marketplace: 'Marketplace', + arrange: '編排', + install: '安裝', + installFromGithub: '從 GitHub 安裝外掛', + onlySupportGithub: '目前僅支援從 GitHub 安裝', + enterGithubLink: '請輸入外掛的Github連結', + installing: '正在安裝外掛...', + installSuccess: '外掛安裝成功', + installFailed: '外掛安裝失敗:', + searchPlugin: '搜尋外掛', + sortBy: '排序方式', + mostStars: '最多星標', + recentlyAdded: '最近新增', + recentlyUpdated: '最近更新', + noMatchingPlugins: '沒有找到符合的外掛', + loading: '載入中...', + getPluginListError: '取得外掛清單失敗:', + pluginConfig: '外掛設定', + noPluginInstalled: '暫未安裝任何外掛', + pluginSort: '外掛排序', + pluginSortDescription: + '外掛順序會影響同一事件內的處理順序,請拖曳外掛卡片排序', + pluginSortSuccess: '外掛排序成功', + pluginSortError: '外掛排序失敗:', + pluginNoConfig: '外掛沒有設定項目。', + deleting: '刪除中...', + deletePlugin: '刪除外掛', + cancel: '取消', + saveConfig: '儲存設定', + saving: '儲存中...', + confirmDeletePlugin: '您確定要刪除外掛({{author}}/{{name}})嗎?', + confirmDelete: '確認刪除', + deleteError: '刪除失敗:', + close: '關閉', + deleteConfirm: '刪除確認', + modifyFailed: '修改失敗:', + eventCount: '事件:{{count}}', + toolCount: '工具:{{count}}', + starCount: '星標:{{count}}', + }, + pipelines: { + title: '流程線', + description: '流程線定義了對訊息事件的處理流程,用於綁定到機器人', + createPipeline: '建立流程線', + editPipeline: '編輯流程線', + chat: '對話', + configuration: '設定', + debugChat: '對話除錯', + getPipelineListError: '取得流程線清單失敗:', + daysAgo: '天前', + today: '今天', + updateTime: '更新於', + defaultBadge: '預設', + sortBy: '排序方式', + newestCreated: '最新建立', + recentlyEdited: '最近編輯', + earliestEdited: '最早編輯', + basicInfo: '基本資訊', + aiCapabilities: 'AI 能力', + triggerConditions: '觸發條件', + safetyControls: '安全控制', + outputProcessing: '輸出處理', + nameRequired: '名稱不能為空', + descriptionRequired: '描述不能為空', + createSuccess: '建立成功 請編輯流程線詳細參數', + createError: '建立失敗:', + saveSuccess: '儲存成功', + saveError: '儲存失敗:', + deleteConfirmation: + '您確定要刪除這個流程線嗎?已綁定此流程線的機器人將無法使用。', + defaultPipelineCannotDelete: '預設流程線不可刪除', + deleteSuccess: '刪除成功', + deleteError: '刪除失敗:', + debugDialog: { + title: '流程線對話', + selectPipeline: '選擇流程線', + sessionType: '對話類型', + privateChat: '私聊', + groupChat: '群聊', + send: '傳送', + reset: '重設對話', + inputPlaceholder: '傳送 {{type}} 訊息...', + noMessages: '暫無訊息', + userMessage: '使用者', + botMessage: '機器人', + sendFailed: '傳送失敗', + resetSuccess: '對話已重設', + resetFailed: '重設失敗', + loadMessagesFailed: '載入訊息失敗', + loadPipelinesFailed: '載入流程線失敗', + atTips: '提及機器人', + }, + }, + knowledge: { + title: '知識庫', + createKnowledgeBase: '建立知識庫', + editKnowledgeBase: '編輯知識庫', + selectKnowledgeBase: '選擇知識庫', + empty: '無', + editDocument: '文件', + description: '設定可用於提升模型回覆品質的知識庫', + metadata: '中繼資料', + documents: '文件', + kbNameRequired: '知識庫名稱不能為空', + kbDescriptionRequired: '知識庫描述不能為空', + embeddingModelUUIDRequired: '嵌入模型不能為空', + daysAgo: '天前', + today: '今天', + kbName: '知識庫名稱', + kbDescription: '知識庫描述', + defaultDescription: '一個知識庫', + embeddingModelUUID: '嵌入模型', + selectEmbeddingModel: '選擇嵌入模型', + embeddingModelDescription: '用於向量化文字,可在模型設定頁面設定', + updateTime: '更新於', + cannotChangeEmbeddingModel: '知識庫建立後不可修改嵌入模型', + updateKnowledgeBaseSuccess: '知識庫更新成功', + updateKnowledgeBaseFailed: '知識庫更新失敗', + documentsTab: { + name: '名稱', + status: '狀態', + noResults: '暫無文件', + dragAndDrop: '拖曳檔案到此處或點擊上傳', + uploading: '上傳中...', + supportedFormats: '支援 PDF、Word、TXT、Markdown 等文件格式', + uploadSuccess: '檔案上傳成功!', + uploadError: '檔案上傳失敗,請重試', + uploadingFile: '上傳檔案中...', + actions: '操作', + delete: '刪除檔案', + fileDeleteSuccess: '檔案刪除成功', + fileDeleteFailed: '檔案刪除失敗', + processing: '處理中', + completed: '完成', + failed: '失敗', + }, + deleteKnowledgeBaseConfirmation: + '您確定要刪除這個知識庫嗎?此知識庫下的所有文件將被刪除。', + retrieve: '檢索測試', + retrieveTest: '檢索測試', + query: '查詢', + queryPlaceholder: '輸入查詢內容...', + distance: '距離', + content: '內容', + fileName: '檔案名稱', + noResults: '暫無結果', + retrieveError: '檢索失敗', + }, + register: { + title: '初始化 LangBot 👋', + description: '這是您首次啟動 LangBot', + adminAccountNote: '您填寫的電子郵件和密碼將作為初始管理員帳號', + register: '註冊', + initSuccess: '初始化成功 請登入', + initFailed: '初始化失敗:', + }, + resetPassword: { + title: '重設密碼 🔐', + description: '輸入恢復金鑰和新的密碼來重設您的帳戶密碼', + recoveryKey: '恢復金鑰', + recoveryKeyDescription: + '儲存在設定檔案`data/config.yaml`的`system.recovery_key`中', + newPassword: '新密碼', + enterRecoveryKey: '輸入恢復金鑰', + enterNewPassword: '輸入新密碼', + recoveryKeyRequired: '恢復金鑰不能為空', + newPasswordRequired: '新密碼不能為空', + resetPassword: '重設密碼', + resetting: '重設中...', + resetSuccess: '密碼重設成功,請登入', + resetFailed: '密碼重設失敗,請檢查電子郵件和恢復金鑰是否正確', + backToLogin: '返回登入', + }, + embedding: { + description: '管理嵌入模型,用於向量化文字', + createModel: '建立嵌入模型', + editModel: '編輯嵌入模型', + getModelListError: '取得嵌入模型清單失敗:', + embeddingModels: '嵌入模型', + extraParametersDescription: + '將在請求時附加到請求體中,如 encoding_format, dimensions 等', + }, + llm: { + llmModels: '對話模型', + description: '管理 LLM 模型,用於對話訊息產生', + extraParametersDescription: + '將在請求時附加到請求體中,如 max_tokens, temperature, top_p 等', + }, +}; + +export default zhHant;