diff --git a/openless-all/app/src/components/SettingsModal.tsx b/openless-all/app/src/components/SettingsModal.tsx index d32a4295..0f85aa81 100644 --- a/openless-all/app/src/components/SettingsModal.tsx +++ b/openless-all/app/src/components/SettingsModal.tsx @@ -333,6 +333,7 @@ function LanguagePicker() { > + ); diff --git a/openless-all/app/src/i18n/en.ts b/openless-all/app/src/i18n/en.ts index 069b6f52..00e5c607 100644 --- a/openless-all/app/src/i18n/en.ts +++ b/openless-all/app/src/i18n/en.ts @@ -391,6 +391,7 @@ export const en: typeof zhCN = { labelDesc: 'Choose "Follow system" to match the OS language at launch.', followSystem: 'Follow system', zh: '简体中文', + zhTW: '繁體中文', en: 'English', restartHint: 'Some native menus (system tray, etc.) may require an app restart to fully switch.', }, diff --git a/openless-all/app/src/i18n/index.ts b/openless-all/app/src/i18n/index.ts index d326eaa7..b366837a 100644 --- a/openless-all/app/src/i18n/index.ts +++ b/openless-all/app/src/i18n/index.ts @@ -12,8 +12,9 @@ import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import { en } from './en'; import { zhCN } from './zh-CN'; +import { zhTW } from './zh-TW'; -export const SUPPORTED_LOCALES = ['zh-CN', 'en'] as const; +export const SUPPORTED_LOCALES = ['zh-CN', 'zh-TW', 'en'] as const; export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number]; export const LOCALE_STORAGE_KEY = 'ol.locale'; @@ -22,14 +23,17 @@ const FOLLOW_SYSTEM_VALUE = 'system'; function detectSystemLocale(): SupportedLocale { if (typeof navigator === 'undefined') return 'zh-CN'; const nav = (navigator.language || '').toLowerCase(); - if (nav.startsWith('zh')) return 'zh-CN'; + if (nav.startsWith('zh')) { + if (nav.includes('hant') || nav.includes('tw') || nav.includes('hk') || nav.includes('mo')) return 'zh-TW'; + return 'zh-CN'; + } return 'en'; } function getStoredLocale(): SupportedLocale | null { if (typeof window === 'undefined') return null; const raw = window.localStorage.getItem(LOCALE_STORAGE_KEY); - return raw === 'zh-CN' || raw === 'en' ? raw : null; + return raw === 'zh-CN' || raw === 'zh-TW' || raw === 'en' ? raw : null; } const initialLng: SupportedLocale = getStoredLocale() ?? detectSystemLocale(); @@ -37,6 +41,7 @@ const initialLng: SupportedLocale = getStoredLocale() ?? detectSystemLocale(); void i18n.use(initReactI18next).init({ resources: { 'zh-CN': { translation: zhCN }, + 'zh-TW': { translation: zhTW }, en: { translation: en }, }, lng: initialLng, diff --git a/openless-all/app/src/i18n/zh-CN.ts b/openless-all/app/src/i18n/zh-CN.ts index d156ef1c..9ed8912e 100644 --- a/openless-all/app/src/i18n/zh-CN.ts +++ b/openless-all/app/src/i18n/zh-CN.ts @@ -389,6 +389,7 @@ export const zhCN = { labelDesc: '选择「跟随系统」时按操作系统当前语言显示。', followSystem: '跟随系统', zh: '简体中文', + zhTW: '繁體中文', en: 'English', restartHint: '部分原生菜单(系统托盘等)可能需要重启 App 才会切换。', }, diff --git a/openless-all/app/src/i18n/zh-TW.ts b/openless-all/app/src/i18n/zh-TW.ts new file mode 100644 index 00000000..5bd7fa0f --- /dev/null +++ b/openless-all/app/src/i18n/zh-TW.ts @@ -0,0 +1,515 @@ +import type { zhCN } from './zh-CN'; + +// 繁體中文資源 — 與產品當前文案保持一致。 +// 新增 key 時,必須同步更新 en.ts,避免切換到 English 後出現中文殘留。 + +export const zhTW: typeof zhCN = { + app: { + name: 'OpenLess', + tagline: '自然說話,完美書寫', + }, + common: { + loading: '加載中…', + refresh: '刷新', + clear: '清空', + copy: '複製', + delete: '刪除', + later: '稍後', + cancel: '取消', + close: '關閉', + show: '顯示', + hide: '隱藏', + saved: '已保存', + saving: '保存中', + copied: '已複製', + operationFailed: '操作失敗', + add: '添加', + durationSeconds: '{{value}} 秒', + durationMinutes: '{{value}} 分鐘', + }, + capsule: { + thinking: '正在思考中', + cancelled: '已取消', + error: '出錯了', + inserted: '已插入 {{count}}', + translating: '正在翻譯', + }, + qa: { + thinking: '思考中…', + error: '出錯了,請稍後再試。', + errorRetry: '重試', + errorRetryHint: '再按 {{recordHotkey}} 重新提問。', + pinTooltip: '固定(不自動關閉)', + unpinTooltip: '取消固定', + closeTooltip: '關閉', + selectionPreview: '基於選中文本:', + emptyTitle: '按 {{recordHotkey}} 開始提問', + emptyDesc: '在任意 app 選中一段文字後,按一次 {{recordHotkey}} 開始錄音,再按一次結束並提交。回答會顯示在這裏,可以連續多輪追問。', + recordingHint: '錄音中…再按一次 {{recordHotkey}} 結束並提問', + statusIdle: '按 {{recordHotkey}} 提問', + statusRecording: '錄音中', + statusThinking: '思考中', + statusError: '出錯了', + }, + nav: { + overview: '概覽', + history: '歷史', + vocab: '詞彙表', + style: '風格', + translation: '翻譯', + selectionAsk: '劃詞追問', + }, + shell: { + shortcutLabel: '錄音快捷鍵', + shortcutHint: '開始 / 停止', + betaTag: 'BETA', + betaNote: '所有數據都只保存在本機。', + footer: { + account: '賬戶', + feedback: '反饋', + settings: '設置', + help: '幫助', + version: '版本 {{version}}', + helpPopover: { + tagline: '本地驅動的語音輸入層', + releaseNotes: '查看發佈日誌 ↗', + docs: '幫助中心 ↗', + }, + }, + providerPrompt: { + title: '設置語音提供商', + body: '還沒有配置 ASR 或 LLM 提供商,語音輸入和潤色暫時無法正常工作。', + later: '稍後', + openSettings: '去設置', + }, + hotkeyModePrompt: { + title: '檢查錄音方式', + body: '本版本默認改爲“切換式說話”。如果你之前改過快捷鍵觸發方式,請到“錄音”裏手動確認一次。本次更新同時調整了快捷鍵方式的讀取邏輯;如果你更習慣按住說話,可以重新切回“按住說話”。', + later: '稍後提醒', + openSettings: '去錄音設置', + }, + }, + onboarding: { + welcome: '歡迎使用 OpenLess', + intro: '本地說出,本地落字。開始前需要兩個系統權限。', + accessibilityTitle: '輔助功能', + hotkeyTitle: '全局快捷鍵', + accessibilityDesc: '用於監聽全局快捷鍵(默認 {{trigger}})並把識別結果寫入光標位置。', + hotkeyDesc: '用於確認全局快捷鍵監聽可用。', + micTitle: '麥克風', + micDesc: '用於捕獲你的語音輸入。', + actionNotApplicable: '無需授權', + actionGranted: '已授權', + actionOpenSystem: '打開系統設置', + actionGrant: '授權', + actionRequestMic: '彈出授權', + accessibilityHint: '授權後必須**完全退出 OpenLess** 再重新打開(macOS TCC 規則)。', + footerHint: '授權全部完成後此引導自動關閉。如果一直不消失,從菜單欄 OpenLess → 退出,重新打開 App。', + }, + overview: { + kicker: 'DASHBOARD', + title: '今日概覽', + desc: '本地說出,本地落字。下面是你今日的口述節奏與系統狀態。', + pressPrefix: '按', + pressSuffix: '開始錄音', + asrKind: 'ASR 語音', + llmKind: 'LLM 模型', + asrName: '火山引擎', + asrSubname: 'bigmodel', + llmName: 'OpenAI 兼容', + llmConfigured: '已配置 active LLM', + llmNotConfigured: '未配置', + statusConfigured: '已配置', + statusNotConfigured: '未配置', + metricChars: '今日字數', + metricSegments: '{{count}} 段', + metricDuration: '今日總時長', + metricAvg: '平均段落', + metricAvgTrend: '今日均值', + metricNoData: '暫無數據', + metricTotal: '累計記錄', + metricTotalTrend: '本機存檔 (上限 200)', + weekTitle: '近 7 天', + weekUnit: '條數 / 天', + recentTitle: '最近識別', + recentAll: '全部記錄 →', + recentEmpty: '還沒有記錄。按 {{trigger}} 開始第一次錄音。', + weekDays: ['日', '一', '二', '三', '四', '五', '六'], + }, + history: { + kicker: 'HISTORY', + title: '歷史記錄', + desc: '最近的識別結果只保存在本機。左側爲時間線,右側爲原文與潤色對比。', + filterAll: '全部', + summary: '共 {{total}} 條 · 顯示 {{shown}}', + empty: '還沒有歷史記錄。按 {{trigger}} 錄一段試試。', + rawLabel: '原文', + rawEmpty: '(空)', + selectHint: '左側選一條查看詳情。', + insertedTo: '插入到', + chars: '{{count}} 字', + vocabHits: '{{count}} 個熱詞', + inserted: '已插入', + pasteSent: '已嘗試粘貼', + copiedFallback: '已複製(需 {{shortcut}})', + insertFailed: '插入失敗', + confirmClear: '確定清空全部 {{count}} 條記錄?此操作不可恢復。', + }, + vocab: { + kicker: 'VOCABULARY', + title: '詞彙表', + desc: '告訴模型識別前可能出現的詞——生詞、新詞或專業詞彙。同時進入 ASR 熱詞與後期模型上下文。', + placeholder: '輸入詞語,按 Enter 或點添加…', + tip: '支持中英混合 · 數字開頭按字面識別 · 命中次數自動計數', + loadFailed: '加載失敗:{{err}}', + empty: '還沒有詞條。在上面輸入一個生詞或專業術語,讓模型在聽寫時優先匹配。', + tipDisabled: '點擊禁用此詞條', + tipEnabled: '點擊啓用此詞條', + removeAria: '刪除', + presets: { + title: '場景預設', + tip: '可多選後批量啓用;支持編輯和新建,已爲後續導入導出預留本地結構。', + create: '新建預設', + apply: '啓用所選', + save: '保存預設', + edit: '編輯 {{name}}', + newPreset: '新預設', + namePlaceholder: '預設名稱', + wordsPlaceholder: '詞條(用逗號或換行分隔)', + }, + }, + style: { + kicker: 'STYLE', + title: '輸出風格', + desc: '選擇默認風格用於全局錄音。每張卡可單獨啓停;啓停的風格不會出現在歷史記錄的「重新潤色」切換中。', + masterToggle: '整體啓用', + currentDefault: '當前默認', + ariaSetDefault: '設爲默認', + modes: { + raw: { name: '原文', desc: '只補標點和必要分句,不改寫不擴寫。', sample: '保留原始口語;嗯、那個等口癖會被去除,但不會重組語句。' }, + light: { name: '輕度潤色', desc: '去口癖、補標點,整理爲可發送的自然文字。', sample: '讓轉寫聽起來不像念稿——保留語氣和表達習慣,但行文流暢。' }, + structured: { name: '清晰結構', desc: '多個主題或步驟時,自動組織爲分點列表。', sample: '1. 主題一\na. 要點\nb. 要點\n2. 主題二\na. 要點\nb. 要點' }, + formal: { name: '正式表達', desc: '工作溝通和郵件場景,更專業更完整。', sample: '郵件場景自動識別問候 / 落款;不引入空泛客套。' }, + }, + }, + translation: { + kicker: 'TRANSLATION', + title: '翻譯', + desc: '把口述的內容自動翻譯成目標語言後再插入。目標語言、工作語言、觸發方式都在這裏配置。', + statusEnabled: '已啓用', + statusDisabled: '未啓用', + working: { + title: '工作語言', + desc: '勾選你日常會用到的語言(多選)。這組語言會作爲前提注入 LLM 的 system prompt 頭部,影響潤色與翻譯的判斷(專名拼寫、語氣、行文習慣)。', + }, + target: { + title: '翻譯目標語言', + desc: '選了某個語言後,錄音過程中任意時刻按一下 Shift,停止後就會把轉寫翻譯成該語言再插入到光標位置。選「不啓用」則 Shift 沒有任何效果,走普通潤色管線。', + disabled: '不啓用(Shift 按下不觸發翻譯)', + }, + howto: { + title: '使用方法', + step1: '在另一個 app 的輸入框裏聚焦光標(備忘錄、郵件、聊天窗口都行)。', + step2: '按一下"錄音快捷鍵"(當前是 {{trigger}}),開始錄音。', + step3: '在錄音過程中任意時刻按一下 Shift——按一下即可,不需要按住,可以在開口前、說到一半、快說完時按。', + step4: '再按一下"錄音快捷鍵"停止錄音。', + step5: '系統會把轉寫交給大模型翻譯成上面選的目標語言,然後插入到一開始那個輸入框光標位置。', + indicatorTitle: '怎麼知道翻譯模式生效了', + indicatorDesc: '一旦按下 Shift,屏幕底部錄音膠囊的上方會立刻懸浮一個藍色"● 正在翻譯"小藥丸——它會一直顯示到本次插入完成,讓你確認這次輸出會走翻譯管線。', + fallbackTitle: '安全兜底', + fallbackDesc: '翻譯模式選「不啓用」時 Shift 是沒作用的;翻譯過程中如果大模型調用失敗,會回退到把原始中文轉寫直接插入,不會丟字。詳見 issue #4。', + }, + }, + selectionAsk: { + kicker: 'SELECTION ASK', + title: '劃詞追問', + desc: '選中任意 app 裏的一段文字,按 {{hotkey}} 彈出浮窗,再按 {{recordHotkey}} 錄音提問。支持多輪追問,浮窗一直保留直到你手動關。', + statusEnabled: '已啓用', + statusDisabled: '未啓用', + hotkey: { + title: '彈出浮窗的快捷鍵', + desc: '只決定「打開 / 關閉」浮窗。浮窗裏錄音 / 提問統一用 {{recordHotkey}}(與你的主聽寫鍵複用)。選「不啓用」則關閉整個功能。', + optionDisabled: '不啓用', + chordWarning: '', + }, + history: { + title: '保存歷史', + desc: '勾上則把每次追問的「選中文本 + 你的語音問題 + AI 答案」寫入本地存檔(不上雲)。默認關,關閉時浮窗一關問答即遺忘,更注重隱私。', + }, + howto: { + title: '使用方法', + step1: '按「{{hotkey}}」在任意時刻打開浮窗(不需要先選文字)。', + step2: '在任意 app(瀏覽器、Mail、IDE、PDF reader…)裏選中一段文字。', + step3: '按一下 **{{recordHotkey}}**——開始錄音;再按一下 {{recordHotkey}},停止並提交,AI 答案顯示在浮窗裏。', + step4: '同一個浮窗裏可繼續多輪追問:再按 {{recordHotkey}} 錄音 → 再按 {{recordHotkey}} 提交。可以重新選文字讓下一輪帶新選區,也可以不選直接對話。', + step5: '按 Esc 或浮窗右上角 ✕ 關閉,關閉即清空所有多輪歷史。再按「{{hotkey}}」就是一段新的對話。', + windowTitle: '浮窗位置 + 拖動 + 釘住', + windowDesc: '浮窗第一次打開在屏幕底部錄音膠囊正上方;標題欄可拖動,移到任意位置後下一次打開會保留位置(同一次啓動期間)。右上角 📌 釘住時即使重新提問也保留窗口;不釘住按 Esc 即關。', + privacyTitle: '隱私契約', + privacyDesc: '選中的文本只在內存裏活到浮窗關閉,**絕不**寫入歷史存檔(保存歷史開關只控制問答 metadata);超過 4000 字符會截首+尾各 2000 後再上送大模型,避免泄露太多。LLM 調用走你已配的 ARK / DeepSeek 等 OpenAI 兼容 endpoint。', + }, + }, + settings: { + kicker: 'SETTINGS', + title: '設置', + desc: '錄音方式、模型與語音提供商、快捷鍵、權限與關於信息——全部在這裏。', + sections: { + recording: '錄音', + providers: '提供商', + shortcuts: '快捷鍵', + permissions: '權限', + language: '語言', + about: '關於', + }, + recording: { + title: '錄音', + desc: '定義全局錄音的快捷鍵與觸發方式。', + hotkeyLabel: '錄音快捷鍵', + hotkeyDescAcc: '按下即開始捕獲語音,全局生效。需要授予輔助功能權限。', + hotkeyDescNoAcc: '按下即開始捕獲語音,全局生效。無需額外輔助功能授權。', + modeLabel: '錄音方式', + modeDesc: '切換式 = 按一次開始、再按一次結束;按住說話 = 按住開始、鬆開結束。', + modeToggle: '切換式', + modeHold: '按住說話', + migrationNoticeTitle: '默認已改爲切換式說話', + migrationNoticeDesc: '如果你之前改過快捷鍵觸發方式,請在這裏手動確認一次。本次更新調整了快捷鍵方式的默認值與讀取邏輯;如果你更習慣按住說話,可以重新切回“按住說話”。', + capsuleLabel: '錄音膠囊', + capsuleDesc: '錄音 / 轉寫時在屏幕底部顯示半透明膠囊。', + restoreClipboardLabel: '插入後恢復剪貼板', + restoreClipboardDesc: '僅 Windows / Linux:粘貼成功後恢復你原來的剪貼板內容(默認開)。關掉就把聽寫文本留在剪貼板,模擬粘貼沒真正落地時可以手動 Ctrl+V 找回。詳見 issue #111。', + allowNonTsfFallbackLabel: '允許非 TSF 兜底', + allowNonTsfFallbackDesc: '僅 Windows:TSF 直接上屏失敗後,允許改用 Unicode SendInput、快捷鍵粘貼或 WM_PASTE。關閉後可驗證是否真實使用 TSF 輸入。', + startupAtBoot: '開機自啓', + startupAtBootDesc: '登錄後自動啓動 OpenLess。macOS 寫 LaunchAgent,Linux 寫 ~/.config/autostart,Windows 寫 HKCU\\Run(不需要管理員)。詳見 issue #194。', + startupAtBootError: '開機自啓切換失敗:{{message}}', + }, + providers: { + llmTitle: 'LLM 模型(潤色)', + llmDesc: 'OpenAI 兼容協議,支持多家供應商切換。', + providerLabel: '供應商', + llmProviderDesc: '選擇後將自動填入 Base URL 默認值。', + asrProviderDesc: '切換後將自動選用對應憑據。', + asrTitle: 'ASR 語音(轉寫)', + asrDesc: '用於將口述實時轉寫爲文本。', + presets: { + ark: 'ARK(火山方舟)', + deepseek: 'DeepSeek', + siliconflow: '硅基流動', + openai: 'OpenAI', + custom: '自定義', + asrVolcengine: '火山引擎 bigasr', + asrSiliconflow: '硅基流動 SenseVoice', + asrZhipu: '智譜 GLM-ASR', + asrGroq: 'Groq Whisper-large-v3', + asrWhisper: 'OpenAI Whisper(兼容)', + }, + volcengineAppKeyLabel: 'APP ID', + volcengineAccessKeyLabel: 'Access Token', + volcengineResourceIdLabel: 'Resource ID', + volcengineMappingNote: 'Secret Key 當前無需填寫。Resource ID 默認使用 volc.bigasr.sauc.duration。', + fillDefault: '填入默認值', + readFailed: '讀取失敗', + apiKeyLabel: 'API 密鑰', + baseUrlLabel: '接口地址', + modelLabel: '模型', + appIdLabel: 'App ID(應用 ID)', + accessKeyLabel: 'Access Key', + resourceIdLabel: '資源 ID', + toolsLabel: '連接檢查', + toolsDesc: '先保存上方配置,再驗證當前模型連通性或拉取模型;失敗時仍可手動填寫模型 ID。', + validate: '驗證', + validating: '驗證中…', + fetchModels: '拉取模型', + loadingModels: '拉取模型中…', + modelMissing: '未配置模型,請先填寫模型 ID。', + modelsEmpty: '鑑權成功,但沒有返回可用模型。', + modelsLoaded: '已拉取 {{count}} 個模型。', + selectModel: '選擇一個模型寫入上方字段', + modelSaved: '已保存模型 {{model}}。', + validateSuccess: '連接檢查通過。', + providerHttpStatus: '供應商接口返回 {{status}},請檢查 API Key 權限或 Endpoint。', + endpointMustUseHttps: 'Endpoint 必須使用 HTTPS(本地 localhost/127.0.0.1 測試除外)。', + endpointInvalid: 'Endpoint 格式不合法。', + responseTooLarge: '供應商響應過大,已停止驗證以保證安全。', + asrInvalidJson: 'ASR 響應不是有效 JSON。', + asrMissingTextField: 'ASR 響應缺少 text 字段。', + apiKeyMissing: 'API Key 爲空。', + endpointMissing: 'Endpoint 爲空。', + requestTimeout: '請求超時,請稍後重試。', + }, + shortcuts: { + title: '快捷鍵速查', + descAcc: '所有快捷鍵全局生效,需要在權限設置中開啓輔助功能。', + descNoAcc: '所有快捷鍵全局生效。若無響應,請在權限頁查看全局快捷鍵監聽狀態。', + startStop: '開始 / 停止錄音', + cancel: '取消本次錄音', + confirm: '膠囊確認插入', + switchStyle: '切換上一次風格', + openApp: '打開 OpenLess', + confirmHint: '點擊右側 ✓', + notSupported: '暫未支持', + }, + permissions: { + title: '權限', + descAcc: 'OpenLess 需要以下系統權限才能正常工作。授權後通常需要完全退出 App 重啓一次才生效。', + descNoAcc: 'OpenLess 需要麥克風可用,並依賴全局快捷鍵監聽狀態判斷 native hook 是否正常工作。', + micLabel: '麥克風', + micDesc: '用於捕獲你的語音輸入。', + accLabel: '輔助功能', + accDesc: '用於監聽全局快捷鍵並將識別結果寫入光標位置。', + hotkeyLabel: '全局快捷鍵', + hotkeyDescWithAdapter: '當前適配器:{{adapter}}。用於判斷快捷鍵監聽是否已經安裝。', + hotkeyDescPlain: '用於判斷快捷鍵監聽是否已經安裝。', + networkLabel: '網絡', + networkDesc: '雲端 ASR / LLM 調用所必需。本地模式可關閉。', + networkOk: '可用', + checking: '檢查中…', + granted: '已授權', + notApplicable: '無需授權', + denied: '未授權', + indeterminate: '未確定', + openSystem: '打開系統設置', + grant: '授權', + hotkeyInstalled: '已安裝', + hotkeyStarting: '安裝中…', + hotkeyFailed: '監聽失敗', + windowsImeLabel: 'Windows 輸入法後端', + windowsImeDesc: '用於在語音會話期間臨時切換到 OpenLess TSF 輸入法,避免剪貼板插入限制。', + windowsImeInstalled: '已安裝', + windowsImeUnavailable: '不可用', + windowsIme: { + installed: '已安裝。語音輸入時會臨時切換到 OpenLess 輸入法。', + notInstalled: '未安裝。OpenLess 正在使用剪貼板 / WM_PASTE 兜底。', + registrationBroken: '註冊已損壞。請重新安裝 OpenLess 輸入法。', + notWindows: '僅 Windows 可用。', + }, + }, + language: { + title: '界面語言', + desc: '切換 UI 顯示語言。當前會話即時生效,下次啓動自動沿用。', + label: '語言', + labelDesc: '選擇「跟隨系統」時按操作系統當前語言顯示。', + followSystem: '跟隨系統', + zh: '簡體中文', + zhTW: '繁體中文', + en: 'English', + restartHint: '部分原生菜單(系統托盤等)可能需要重啓 App 纔會切換。', + }, + about: { + tagline: '自然說話,完美書寫', + checkUpdate: '檢查更新', + checkUpdateBtn: '檢查', + checkingUpdate: '檢查中…', + upToDate: '當前已是最新版本。', + updateError: '檢查或更新失敗,請稍後重試。', + openReleases: '打開 Releases', + source: '源碼', + docs: '文檔', + feedback: '反饋', + qq: '社區 QQ 羣', + qqDesc: '使用 QQ 搜索羣號加入,或掃碼進羣。', + copyQq: '複製羣號', + privacy: '隱私', + privacyDesc: '所有識別結果僅保存在本機。雲端 API 僅用於實時轉寫與潤色,不會保留你的錄音。', + localFirst: '本地優先', + updateDialog: { + available: { + title: '發現新版本', + desc: '發現 OpenLess {{version}},是否現在更新?', + }, + downloading: { + title: '正在下載更新', + desc: '正在下載 OpenLess {{version}},請保持應用打開。', + }, + downloaded: { + title: '更新已準備好', + desc: 'OpenLess {{version}} 已安裝完成。是否現在自動重啓以應用更新?', + }, + installing: { + title: '正在安裝更新', + desc: '正在安裝 OpenLess {{version}},請保持應用打開。', + }, + install: '現在更新', + downloadingLabel: '下載中…', + installingLabel: '安裝中…', + later: '稍後手動重啓', + restartNow: '現在重啓', + progress: '{{progress}}% · {{downloaded}} / {{total}}', + progressUnknown: '已下載 {{downloaded}}', + }, + }, + }, + modal: { + sections: { + account: '賬戶', + settings: '設置', + personalize: '個性化', + about: '關於', + helpCenter: '幫助中心', + releaseNotes: '版本說明', + }, + account: { + localUser: '本地用戶', + localUserDesc: '未登錄 · 所有數據保存在本機', + loginSync: '登錄 / 同步', + footer: 'OpenLess 默認完全本地運行。登錄後可在多設備間同步詞彙表與風格預設,識別仍在本機或你配置的 Provider 上完成。', + }, + personalize: { + appearance: '外觀', + appearanceDesc: '跟隨系統 / 淺色 / 深色', + appearanceSystem: '跟隨系統', + appearanceLight: '淺色', + appearanceDark: '深色', + language: '界面語言', + font: '字體大小', + fontDesc: '整體縮放界面字號,立即生效。', + fontSmall: '小', + fontMedium: '中', + fontLarge: '大', + blur: '毛玻璃強度', + blurDesc: '影響窗口內層 backdrop-filter 強度(macOS 系統磨砂層無法運行時調)。', + startupOpen: '啓動時打開', + startupOverview: '概覽', + startupLast: '上次位置', + startupAtBoot: '開機自啓', + }, + about: { + tagline: '自然說話,完美書寫', + checkUpdate: '檢查更新', + checkUpdateBtn: '檢查', + docs: '文檔', + docsBtn: 'openless.app/docs ↗', + feedback: '反饋渠道', + feedbackBtn: 'GitHub Issues ↗', + privacy: '隱私', + privacyDesc: '所有識別結果只保存在本機,雲端 API 僅用於實時調用。', + localFirst: '本地優先', + }, + }, + windowChrome: { + minimize: '最小化', + maximize: '最大化', + close: '關閉', + }, + hotkey: { + triggers: { + rightOption: '右 Option', + leftOption: '左 Option', + rightControl: '右 Control', + leftControl: '左 Control', + rightCommand: '右 Command', + fn: 'Fn (地球鍵)', + rightAlt: '右 Alt', + }, + fallback: '全局快捷鍵', + modeHoldSuffix: '(按住說話)', + modeToggleSuffix: '(開始 / 停止)', + usageHold: '按住 {{trigger}} 說話,鬆開結束。', + usageToggle: '按 {{trigger}} 開始錄音,再按一次結束。', + adapter: { + macEventTap: 'macOS Event Tap', + windowsLowLevel: 'Windows 低層鍵盤 hook', + rdev: 'rdev 監聽器', + }, + }, +}; diff --git a/openless-all/app/src/pages/Settings.tsx b/openless-all/app/src/pages/Settings.tsx index 71c1abfd..574d02b9 100644 --- a/openless-all/app/src/pages/Settings.tsx +++ b/openless-all/app/src/pages/Settings.tsx @@ -1096,6 +1096,7 @@ function LanguageSection() { > +