diff --git a/openless-all/app/src/i18n/en.ts b/openless-all/app/src/i18n/en.ts index 0d8bfd98..a262c4ce 100644 --- a/openless-all/app/src/i18n/en.ts +++ b/openless-all/app/src/i18n/en.ts @@ -405,8 +405,8 @@ export const en: typeof zhCN = { zh: '简体中文', zhTW: '繁體中文', en: 'English', - ja: '日本語', - ko: '한국어', + ja: '日本語 (Beta)', + ko: '한국어 (Beta)', restartHint: 'Some native menus (system tray, etc.) may require an app restart to fully switch.', }, about: { diff --git a/openless-all/app/src/i18n/ja.ts b/openless-all/app/src/i18n/ja.ts index 63a11499..17dcc908 100644 --- a/openless-all/app/src/i18n/ja.ts +++ b/openless-all/app/src/i18n/ja.ts @@ -1,17 +1,404 @@ import type { zhCN } from './zh-CN'; import { en } from './en'; -// Japanese locale scaffold (incremental translation over English baseline). +// 日本語 (Beta) — AI 機械翻訳ベース。ネイティブ話者によるレビューを推奨。 +// 構造は zh-CN.ts に追従。新しい key を追加する場合は ja.ts / ko.ts も同時に +// 更新してください(更新されない key は ...en で英語にフォールバックします)。 export const ja: typeof zhCN = { ...en, app: { - ...en.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: '任意のアプリでテキストを選択した後、{{recordHotkey}} を 1 回押して録音を開始し、もう 1 回押して送信します。回答はここに表示され、続けて追加質問が可能です。', + recordingHint: '録音中… {{recordHotkey}} をもう一度押して終了し、質問します', + statusIdle: '{{recordHotkey}} で質問', + statusRecording: '録音中', + statusThinking: '思考中', + statusError: 'エラー', + }, + nav: { + overview: '概要', + history: '履歴', + vocab: '語彙', + style: 'スタイル', + translation: '翻訳', + selectionAsk: '選択追問', + localAsr: 'モデル設定', + }, + 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: 'ローカルで話し、ローカルで文字に。開始前にシステム権限が 2 つ必要です。', + accessibilityTitle: 'アクセシビリティ', + hotkeyTitle: 'グローバルショートカット', + accessibilityDesc: 'グローバルショートカット(既定 {{trigger}})の検知と、認識結果のカーソル位置への入力に使用します。', + hotkeyDesc: 'グローバルショートカット監視が利用可能か確認するために使用します。', + micTitle: 'マイク', + micDesc: '音声入力の取得に使用します。', + actionNotApplicable: '権限不要', + actionGranted: '許可済み', + actionOpenSystem: 'システム設定を開く', + actionGrant: '許可する', + actionRequestMic: '許可ダイアログを表示', + accessibilityHint: '許可後は **OpenLess を完全に終了** してから再起動してください(macOS TCC の仕様)。', + footerHint: 'すべての権限が揃うとこのガイドは自動で閉じます。閉じない場合はメニューバーの OpenLess → 終了 から再起動してください。', + }, + overview: { + kicker: 'DASHBOARD', + title: '本日の概要', + desc: 'ローカルで話し、ローカルで文字に。以下は本日のディクテーションペースとシステム状態です。', + pressPrefix: '押す', + pressSuffix: 'で録音開始', + asrKind: 'ASR 音声', + llmKind: 'LLM モデル', + asrName: 'Volcengine', + asrSubname: 'bigmodel', + llmName: 'OpenAI 互換', + llmConfigured: 'アクティブ 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: '左側から 1 件選択して詳細を表示。', + 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. トピック 1\na. ポイント\nb. ポイント\n2. トピック 2\na. ポイント\nb. ポイント' }, + formal: { name: '正式な表現', desc: '業務コミュニケーションやメール用途向け。よりプロフェッショナルで完成度の高い文体。', sample: 'メール用途では挨拶 / 結びを自動認識します。空疎な定型句は持ち込みません。' }, + }, + }, + translation: { + kicker: 'TRANSLATION', + title: '翻訳', + desc: '口述内容を自動的にターゲット言語へ翻訳してから入力します。ターゲット言語、作業言語、トリガー方式すべてここで設定。', + statusEnabled: '有効', + statusDisabled: '無効', + working: { + title: '作業言語', + desc: '日常的に使用する言語(複数選択可)にチェックを入れてください。これらは前提として LLM の system prompt 冒頭に注入され、整文と翻訳の判断(固有名詞の表記、語気、文体習慣)に影響します。', + }, + target: { + title: '翻訳ターゲット言語', + desc: 'いずれかの言語を選択すると、録音中の任意のタイミングで Shift を 1 回押すだけで、停止後に転写をその言語に翻訳してカーソル位置に入力します。「無効」を選ぶと Shift は何の効果もなく、通常の整文パイプラインに進みます。', + disabled: '無効(Shift で翻訳を発動しない)', + }, + howto: { + title: '使い方', + step1: '別のアプリの入力欄でカーソルにフォーカス(メモ、メール、チャットウィンドウなど)。', + step2: '「録音ショートカット」(現在 {{trigger}})を押して録音開始。', + step3: '録音中の任意のタイミングで Shift を 1 回押す——押し続ける必要はなく、話す前でも途中でも終わり際でも OK。', + step4: 'もう一度「録音ショートカット」を押して停止。', + step5: 'システムが転写を LLM に渡し、上で選んだターゲット言語に翻訳して、最初の入力欄のカーソル位置に挿入します。', + indicatorTitle: '翻訳モードの確認方法', + indicatorDesc: 'Shift を押すと画面下部の録音カプセルの上に青い「● 翻訳中」の小さなピルが浮かびます——本回の入力が完了するまで表示され、翻訳パイプラインに乗ったことを確認できます。', + fallbackTitle: 'セーフティフォールバック', + fallbackDesc: '翻訳モードを「無効」にすると Shift は無効。翻訳中に LLM 呼び出しが失敗した場合は、原文の中国語転写を直接挿入するフォールバックに切り替わり、文字の取りこぼしはありません。詳細は issue #4。', + }, + }, + selectionAsk: { + kicker: 'SELECTION ASK', + title: '選択追問', + desc: '任意のアプリでテキストを選択し {{hotkey}} を押すとフロートウィンドウが開き、{{recordHotkey}} で録音質問できます。複数ターンの追問対応、手動で閉じるまで保持。', + statusEnabled: '有効', + statusDisabled: '無効', + hotkey: { + title: 'フロートウィンドウのショートカット', + desc: '「開く / 閉じる」のみを制御。ウィンドウ内の録音 / 質問は {{recordHotkey}}(メインのディクテーションキーと共用)。「無効」を選ぶと機能全体がオフ。', + optionDisabled: '無効', + chordWarning: '', + }, + history: { + title: '履歴を保存', + desc: 'ON にすると、各追問の「選択テキスト + あなたの音声質問 + AI 回答」をローカルに保存(クラウドへは送信しない)。デフォルト OFF では、フロートウィンドウを閉じると問答が消去されプライバシー優先。', + }, + howto: { + title: '使い方', + step1: '「{{hotkey}}」を押すと任意のタイミングでフロートウィンドウが開きます(先にテキストを選択する必要はありません)。', + step2: '任意のアプリ(ブラウザ、メール、IDE、PDF リーダーなど)でテキストを選択。', + step3: '**{{recordHotkey}}** を押すと録音開始;もう一度 {{recordHotkey}} で停止して送信、AI 回答がフロートウィンドウに表示されます。', + step4: '同じウィンドウで複数ターンの追問が可能:再度 {{recordHotkey}} で録音 → 再度 {{recordHotkey}} で送信。新しい選択を追加することも、選択せずに会話を続けることもできます。', + step5: 'Esc または右上の ✕ で閉じる。閉じるとすべての対話履歴が消去されます。再度「{{hotkey}}」を押すと新しい会話が始まります。', + windowTitle: 'ウィンドウの位置 + ドラッグ + ピン留め', + windowDesc: '初回は画面下部の録音カプセル真上に表示されます。タイトルバーをドラッグで移動でき、移動後の位置は次回開いた時にも保持されます(同じ起動セッション内)。右上の 📌 でピン留めすると再質問してもウィンドウを保持。ピン留めしない場合は Esc で閉じます。', + privacyTitle: 'プライバシー契約', + privacyDesc: '選択テキストはメモリ上のみ、ウィンドウを閉じるまで存在します。**履歴ストレージには絶対に書き込みません**(履歴保存スイッチは問答メタデータのみを制御)。4000 文字を超える場合は前後 2000 文字に切り詰めてから LLM に送信し、過剰な情報漏洩を防ぎます。LLM 呼び出しは設定済みの ARK / DeepSeek など OpenAI 互換エンドポイントを通じて行われます。', + }, + }, settings: { - ...en.settings, + kicker: 'SETTINGS', + title: '設定', + desc: '録音方式、モデルと音声プロバイダー、ショートカット、権限、バージョン情報——すべてここに集約。', + sections: { + recording: '録音', + providers: 'プロバイダー', + shortcuts: 'ショートカット', + permissions: '権限', + language: '言語', + about: '情報', + }, + recording: { + title: '録音', + desc: 'グローバル録音のショートカットとトリガー方式を定義します。', + hotkeyLabel: '録音ショートカット', + hotkeyDescAcc: '押すと音声キャプチャを開始(グローバル)。アクセシビリティ権限が必要です。', + hotkeyDescNoAcc: '押すと音声キャプチャを開始(グローバル)。追加の権限は不要。', + modeLabel: '録音方式', + modeDesc: 'トグル式 = 1 回押して開始、もう 1 回押して終了;押し続けて話す = 押している間だけ録音。', + modeToggle: 'トグル式', + modeHold: '押し続けて話す', + migrationNoticeTitle: 'デフォルトがトグル式に変更されました', + migrationNoticeDesc: '以前にトリガー方式を変更していた場合は、ここで再度確認してください。今回のアップデートではショートカット方式のデフォルト値と読み込みロジックが変更されています。「押し続けて話す」が好みであれば再度切り替えてください。', + capsuleLabel: '録音カプセル', + capsuleDesc: '録音 / 転写中、画面下部に半透明のカプセルを表示。', + muteDuringRecordingLabel: '録音中はミュート', + muteDuringRecordingDesc: '音声入力開始時にシステム出力を一時的にミュートし、停止/キャンセル/エラー後に元のミュート状態を復元。スピーカーの音がマイクに入らないようにします。', + restoreClipboardLabel: '入力後にクリップボードを復元', + restoreClipboardDesc: 'Windows / Linux のみ:ペースト成功後に元のクリップボード内容を復元(既定 ON)。OFF にするとディクテーションテキストがクリップボードに残り、ペーストが効かなかった場合に手動で Ctrl+V できます。詳細は issue #111。', + allowNonTsfFallbackLabel: '非 TSF フォールバックを許可', + allowNonTsfFallbackDesc: 'Windows のみ:TSF による直接入力が失敗した場合、Unicode SendInput / ショートカットペースト / WM_PASTE への切り替えを許可。OFF にすると 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(Volcengine Ark)', + deepseek: 'DeepSeek', + siliconflow: 'SiliconFlow', + openai: 'OpenAI', + custom: 'カスタム', + asrVolcengine: 'Volcengine bigasr', + asrSiliconflow: 'SiliconFlow SenseVoice', + asrZhipu: 'Zhipu GLM-ASR', + asrGroq: 'Groq Whisper-large-v3', + asrWhisper: 'OpenAI Whisper(互換)', + asrLocalQwen3: 'ローカル Qwen3-ASR', + }, + volcengineAppKeyLabel: 'APP ID', + volcengineAccessKeyLabel: 'Access Token', + volcengineResourceIdLabel: 'Resource ID', + volcengineMappingNote: 'Secret Key は現在不要。Resource ID のデフォルトは volc.bigasr.sauc.duration。', + localAsrHint: 'ローカル Qwen3-ASR は本機で実行されるため API Key 不要。HuggingFace からモデルをダウンロードすればすぐに利用できます。', + localAsrPerformanceWarning: 'ローカル推論は CPU + Apple Silicon Accelerate で動作するため、1 回の転写時間は **クラウド ASR より数秒長くなります**。中国語認識精度や方言/訛り対応も **通常は** Volcengine / Whisper turbo に劣ります。ネットワーク制限下またはプライバシー重視の場合に選択してください。', + localAsrReady: '{{model}} ダウンロード済み', + localAsrNotReady: '{{model}} 未ダウンロード', + localAsrGoDownload: 'モデル設定でダウンロード', + localAsrManage: 'モデル設定を開く', + localAsrDownloadedTitle: 'ダウンロード済みモデル', + localAsrDelete: '削除', + fillDefault: 'デフォルト値を入力', + readFailed: '読み込み失敗', + apiKeyLabel: 'API キー', + baseUrlLabel: 'エンドポイント', + modelLabel: 'モデル', + appIdLabel: 'App ID(アプリケーション ID)', + accessKeyLabel: 'Access Key', + resourceIdLabel: 'Resource ID', + toolsLabel: '接続チェック', + toolsDesc: '上記の設定を保存してから、現在のモデル接続性を検証またはモデル一覧を取得します。失敗してもモデル ID を手動入力できます。', + validate: '検証', + validating: '検証中…', + fetchModels: 'モデル一覧', + loadingModels: 'モデル取得中…', + modelMissing: 'モデルが未設定です。先にモデル ID を入力してください。', + modelsEmpty: '認証成功ですが、利用可能なモデルが返されませんでした。', + modelsLoaded: '{{count}} 個のモデルを取得しました。', + selectModel: 'モデルを選んで上記欄に入力', + modelSaved: 'モデル {{model}} を保存しました。', + validateSuccess: '接続チェックに合格しました。', + providerHttpStatus: 'サプライヤーが {{status}} を返しました。API Key 権限またはエンドポイントを確認してください。', + 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 はマイクへのアクセスと、グローバルショートカット監視状態を通じてネイティブフックの正常動作を判定する必要があります。', + 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 IME へ一時的に切り替え、クリップボード入力の制限を回避します。', + windowsImeInstalled: 'インストール済み', + windowsImeUnavailable: '利用不可', + windowsIme: { + installed: 'インストール済み。音声入力時に OpenLess IME へ一時的に切り替えます。', + notInstalled: '未インストール。OpenLess は現在クリップボード / WM_PASTE フォールバックを使用しています。', + registrationBroken: '登録が破損しています。OpenLess IME を再インストールしてください。', + notWindows: 'Windows のみ利用可能。', + }, + }, language: { - ...en.settings.language, title: '表示言語', desc: 'UI の表示言語を切り替えます。現在のセッションに即時反映され、次回起動時も維持されます。', label: '言語', @@ -20,16 +407,167 @@ export const ja: typeof zhCN = { zh: '简体中文', zhTW: '繁體中文', en: 'English', - ja: '日本語', - ko: '한국어', + ja: '日本語 (Beta)', + ko: '한국어 (Beta)', restartHint: '一部のネイティブメニュー(トレイ等)は再起動後に反映されます。', }, + about: { + tagline: '自然に話し、きれいに書く', + checkUpdate: 'アップデート確認', + checkUpdateBtn: '確認', + checkingUpdate: '確認中…', + upToDate: '現在最新バージョンです。', + updateError: '確認またはアップデートに失敗しました。後で再試行してください。', + openReleases: 'Releases を開く', + source: 'ソース', + docs: 'ドキュメント', + feedback: 'フィードバック', + qq: 'コミュニティ QQ グループ', + qqDesc: 'QQ でグループ番号を検索して参加するか、QR コードをスキャンしてください。', + 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: { - ...en.modal, + sections: { + account: 'アカウント', + settings: '設定', + personalize: 'パーソナライズ', + about: '情報', + helpCenter: 'ヘルプセンター', + releaseNotes: 'リリースノート', + }, + account: { + localUser: 'ローカルユーザー', + localUserDesc: '未ログイン · すべてのデータはローカルに保存', + loginSync: 'ログイン / 同期', + footer: 'OpenLess は既定で完全にローカルで動作します。ログインすると複数デバイス間で語彙とスタイルプリセットを同期できますが、認識は本機または設定済みプロバイダーで行われます。', + }, personalize: { - ...en.modal.personalize, + appearance: '外観', + appearanceDesc: 'システムに従う / ライト / ダーク', + appearanceSystem: 'システムに従う', + appearanceLight: 'ライト', + appearanceDark: 'ダーク', language: '表示言語', + font: 'フォントサイズ', + fontDesc: 'UI のフォントサイズを全体的にスケール。即時反映。', + 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}} で録音開始、もう 1 回押して終了。', + adapter: { + macEventTap: 'macOS Event Tap', + windowsLowLevel: 'Windows 低レベルキーボードフック', + rdev: 'rdev リスナー', + }, + }, + localAsr: { + kicker: 'ローカル ASR', + title: 'モデル設定', + desc: 'ローカル Qwen3-ASR エンジンとモデル管理。HuggingFace から本機にモデルをダウンロードすれば、ネット接続なしで認識可能。Windows のストリーミング推論は issue を参照。', + engineUnavailable: '現在のプラットフォームではローカル推論エンジンが未統合(macOS のみ対応、Windows は issue #256 で追跡)。モデルのダウンロードは可能ですが、有効化はできません。', + mirrorLabel: 'ダウンロードミラー', + mirrorDesc: '公式ソースは海外ネットワークで安定。hf-mirror.com は中国コミュニティ運営のミラー。', + mirrorHuggingface: 'HuggingFace 公式 (huggingface.co)', + mirrorHfMirror: '中国ミラー (hf-mirror.com)', + activeBadge: '使用中', + downloadedBadge: 'ダウンロード済み', + download: 'ダウンロード', + resume: '続行', + cancel: 'キャンセル', + delete: '削除', + setActive: 'デフォルトに設定', + failed: '失敗', + cancelled: 'キャンセル済み', + files: 'ファイル', + sizeLoading: 'サイズ問い合わせ中…', + sizeUnknown: 'サイズ不明', + performanceWarning: 'ローカル推論は CPU + Apple Silicon Accelerate で動作。**初回転写はモデルロード(数秒)が必要**。以降の転写もクラウド ASR より数秒遅くなります。中国語認識精度や方言/訛り対応も通常は Volcengine / Whisper turbo に劣ります。用途:オフライン / プライバシー重視 / クラウド API 課金を避けたい場合。', + test: 'ロードしてテスト', + testRunning: 'テスト中…', + testHeading: '内蔵オーディオテスト', + testExpected: '原文', + testActual: '認識', + testStats: '音声長 {{audio}}s · ロード {{load}}s · 推論 {{transcribe}}s · バックエンド {{backend}}', + testFailed: 'テスト失敗', + engineStatusLabel: 'メモリ上のエンジン', + engineLoaded: 'ロード済み:{{model}}(約 1.2-3.4 GB のメモリを使用)', + engineUnloaded: '未ロード(初回ディクテーション時に約 3-5 秒のロードが必要)', + loadNow: '今すぐロード', + releaseNow: '今すぐ解放', + keepLoadedLabel: 'ロード保持時間', + keepLoadedDesc: 'ローカル ASR を使用後、何分でメモリから解放するかを決定。1+ GB の RAM 占有を回避。', + keepImmediate: '使用直後に解放', + keep1min: '最終使用から 1 分', + keep5min: '最終使用から 5 分(既定)', + keep30min: '最終使用から 30 分', + keepForever: '解放しない(常にロード)', }, }; diff --git a/openless-all/app/src/i18n/ko.ts b/openless-all/app/src/i18n/ko.ts index d2f13e40..e669e07a 100644 --- a/openless-all/app/src/i18n/ko.ts +++ b/openless-all/app/src/i18n/ko.ts @@ -1,17 +1,404 @@ import type { zhCN } from './zh-CN'; import { en } from './en'; -// Korean locale scaffold (incremental translation over English baseline). +// 한국어 (Beta) — AI 기계 번역 기반. 원어민 검토를 권장합니다. +// 구조는 zh-CN.ts 를 따릅니다. 새 key 를 추가할 때 ja.ts / ko.ts 도 동시에 +// 갱신해 주세요(갱신되지 않은 key 는 ...en 으로 영어로 fallback 됩니다). export const ko: typeof zhCN = { ...en, app: { - ...en.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: '아무 앱에서 텍스트를 선택한 후 {{recordHotkey}} 를 한 번 눌러 녹음을 시작하고, 다시 한 번 눌러 종료 후 제출합니다. 답변이 여기에 표시되며 연속해서 후속 질문이 가능합니다.', + recordingHint: '녹음 중… {{recordHotkey}} 를 다시 눌러 종료하고 질문', + statusIdle: '{{recordHotkey}} 로 질문', + statusRecording: '녹음 중', + statusThinking: '생각 중', + statusError: '오류', + }, + nav: { + overview: '개요', + history: '기록', + vocab: '어휘', + style: '스타일', + translation: '번역', + selectionAsk: '선택 질문', + localAsr: '모델 설정', + }, + 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 → 종료 후 앱을 다시 실행해 주세요.', + }, + overview: { + kicker: 'DASHBOARD', + title: '오늘 개요', + desc: '로컬에서 말하고 로컬에서 입력합니다. 아래는 오늘의 받아쓰기 페이스와 시스템 상태입니다.', + pressPrefix: '누르기', + pressSuffix: '녹음 시작', + asrKind: 'ASR 음성', + llmKind: 'LLM 모델', + asrName: 'Volcengine', + asrSubname: 'bigmodel', + llmName: 'OpenAI 호환', + llmConfigured: '활성 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. 주제 1\na. 포인트\nb. 포인트\n2. 주제 2\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: '다른 앱의 입력 상자에서 커서에 포커스합니다(메모, 메일, 채팅 창 모두 가능).', + step2: '"녹음 단축키"(현재 {{trigger}})를 한 번 눌러 녹음 시작.', + step3: '녹음 중 임의의 시점에 Shift 를 한 번 누름 — 한 번이면 충분하고 누르고 있을 필요 없음. 말하기 전, 도중, 끝날 무렵 모두 가능.', + step4: '"녹음 단축키"를 다시 눌러 녹음 정지.', + step5: '시스템이 전사를 LLM 에 넘겨 위에서 선택한 대상 언어로 번역한 후 처음 입력 상자의 커서 위치에 삽입합니다.', + indicatorTitle: '번역 모드 활성화 확인 방법', + indicatorDesc: 'Shift 를 누르면 화면 하단 녹음 캡슐 위에 파란색 "● 번역 중" 작은 알약이 즉시 나타납니다 — 이번 입력이 완료될 때까지 표시되어 번역 파이프라인을 거친다는 것을 확인할 수 있습니다.', + fallbackTitle: '안전 폴백', + fallbackDesc: '번역 모드가 "비활성화"이면 Shift 는 효과가 없습니다. 번역 도중 LLM 호출이 실패하면 원본 중국어 전사를 직접 삽입하는 폴백이 작동하여 글자가 손실되지 않습니다. 자세한 내용은 issue #4 참조.', + }, + }, + selectionAsk: { + kicker: 'SELECTION ASK', + title: '선택 질문', + desc: '아무 앱에서 텍스트를 선택하고 {{hotkey}} 로 플로팅 창을 띄운 후 {{recordHotkey}} 로 녹음 질문. 다중 라운드 후속 질문 지원, 수동으로 닫을 때까지 유지.', + statusEnabled: '활성화됨', + statusDisabled: '비활성화됨', + hotkey: { + title: '플로팅 창 단축키', + desc: '"열기 / 닫기"만 결정. 창 안의 녹음 / 질문은 모두 {{recordHotkey}} 사용(메인 받아쓰기 키와 공유). "비활성화" 선택 시 기능 전체가 꺼집니다.', + optionDisabled: '비활성화', + chordWarning: '', + }, + history: { + title: '기록 저장', + desc: '체크 시 매 후속 질문의 "선택 텍스트 + 음성 질문 + AI 답변"을 로컬 보관(클라우드 비전송). 기본 OFF 일 때는 창을 닫으면 문답이 즉시 사라져 프라이버시 우선.', + }, + howto: { + title: '사용 방법', + step1: '"{{hotkey}}" 를 눌러 임의의 시점에 플로팅 창을 엽니다(텍스트를 먼저 선택할 필요 없음).', + step2: '아무 앱(브라우저, Mail, IDE, PDF 리더 등)에서 텍스트를 선택합니다.', + step3: '**{{recordHotkey}}** 를 한 번 누르면 녹음 시작; 다시 {{recordHotkey}} 를 누르면 정지하고 제출, AI 답변이 창에 표시됩니다.', + step4: '같은 창에서 다중 라운드 후속 질문 가능: 다시 {{recordHotkey}} 로 녹음 → 다시 {{recordHotkey}} 로 제출. 새 텍스트를 선택해 다음 라운드에 새 선택 영역을 가져갈 수도, 선택 없이 대화를 이어갈 수도 있습니다.', + step5: 'Esc 또는 창 우측 상단 ✕ 로 닫기. 닫으면 모든 다중 라운드 기록이 지워집니다. 다시 "{{hotkey}}" 를 누르면 새 대화가 시작됩니다.', + windowTitle: '창 위치 + 드래그 + 고정', + windowDesc: '창은 처음에 화면 하단 녹음 캡슐 바로 위에 표시됩니다. 타이틀바를 드래그해 임의 위치로 이동 가능하고, 다음에 열 때 위치가 유지됩니다(같은 시작 세션 내). 우측 상단 📌 로 고정하면 재질문해도 창이 유지됩니다. 고정하지 않으면 Esc 로 닫힙니다.', + privacyTitle: '프라이버시 계약', + privacyDesc: '선택 텍스트는 메모리에서만 창이 닫힐 때까지 살아있으며, **기록 저장소에는 절대 기록되지 않습니다**(기록 저장 스위치는 문답 메타데이터만 제어). 4000자를 초과하면 앞뒤 각 2000자로 잘라서 LLM 에 전송하여 과도한 정보 누출을 방지합니다. LLM 호출은 이미 설정된 ARK / DeepSeek 등 OpenAI 호환 엔드포인트를 통해 이루어집니다.', + }, + }, settings: { - ...en.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: '녹음 / 전사 중 화면 하단에 반투명 캡슐을 표시합니다.', + muteDuringRecordingLabel: '녹음 중 음소거', + muteDuringRecordingDesc: '음성 입력 시작 시 시스템 출력을 일시적으로 음소거하고, 정지/취소/오류 후 원래 음소거 상태를 복원합니다. 스피커 소리가 마이크에 들어가지 않도록 합니다.', + restoreClipboardLabel: '입력 후 클립보드 복원', + restoreClipboardDesc: 'Windows / Linux 만: 붙여넣기 성공 후 원래 클립보드 내용을 복원합니다(기본 ON). OFF 시 받아쓰기 텍스트가 클립보드에 남아 붙여넣기가 실패한 경우 수동으로 Ctrl+V 할 수 있습니다. issue #111 참조.', + allowNonTsfFallbackLabel: '비 TSF 폴백 허용', + allowNonTsfFallbackDesc: 'Windows 만: TSF 직접 입력이 실패할 경우 Unicode SendInput / 단축키 붙여넣기 / WM_PASTE 로 전환을 허용합니다. OFF 시 실제로 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 (Volcengine Ark)', + deepseek: 'DeepSeek', + siliconflow: 'SiliconFlow', + openai: 'OpenAI', + custom: '사용자 정의', + asrVolcengine: 'Volcengine bigasr', + asrSiliconflow: 'SiliconFlow SenseVoice', + asrZhipu: 'Zhipu GLM-ASR', + asrGroq: 'Groq Whisper-large-v3', + asrWhisper: 'OpenAI Whisper(호환)', + asrLocalQwen3: '로컬 Qwen3-ASR', + }, + volcengineAppKeyLabel: 'APP ID', + volcengineAccessKeyLabel: 'Access Token', + volcengineResourceIdLabel: 'Resource ID', + volcengineMappingNote: 'Secret Key 는 현재 입력 불필요. Resource ID 기본값은 volc.bigasr.sauc.duration.', + localAsrHint: '로컬 Qwen3-ASR 은 본 기기에서 실행되며 API Key 가 필요 없습니다. HuggingFace 에서 모델을 로컬로 다운로드하면 즉시 사용 가능합니다.', + localAsrPerformanceWarning: '로컬 추론은 CPU + Apple Silicon Accelerate 에서 동작하므로, 한 번의 전사 시간이 **클라우드 ASR 보다 몇 초 더 걸립니다**. 중국어 인식 정확도와 방언/억양 대응도 **일반적으로** Volcengine / Whisper turbo 에 미치지 못합니다. 네트워크 제한 또는 프라이버시가 중요한 경우에 사용하세요.', + localAsrReady: '{{model}} 다운로드됨', + localAsrNotReady: '{{model}} 다운로드되지 않음', + localAsrGoDownload: '모델 설정에서 다운로드', + localAsrManage: '모델 설정으로 이동', + localAsrDownloadedTitle: '다운로드된 모델', + localAsrDelete: '삭제', + fillDefault: '기본값 입력', + readFailed: '읽기 실패', + apiKeyLabel: 'API 키', + baseUrlLabel: '엔드포인트', + modelLabel: '모델', + appIdLabel: 'App ID(애플리케이션 ID)', + accessKeyLabel: 'Access Key', + resourceIdLabel: 'Resource 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 가 정상 작동하려면 다음 시스템 권한이 필요합니다. 허용 후에는 일반적으로 앱을 완전히 종료한 후 재시작해야 적용됩니다.', + descNoAcc: 'OpenLess 는 마이크 사용과 전역 단축키 감지 상태를 통해 네이티브 후크의 정상 동작을 판정해야 합니다.', + 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: { - ...en.settings.language, title: '인터페이스 언어', desc: 'UI 표시 언어를 전환합니다. 현재 세션에 즉시 반영되며 다음 실행에도 유지됩니다.', label: '언어', @@ -20,16 +407,167 @@ export const ko: typeof zhCN = { zh: '简体中文', zhTW: '繁體中文', en: 'English', - ja: '日本語', - ko: '한국어', + ja: '日本語 (Beta)', + ko: '한국어 (Beta)', restartHint: '일부 네이티브 메뉴(트레이 등)는 앱 재시작 후 반영될 수 있습니다.', }, + about: { + tagline: '자연스럽게 말하고, 정확하게 작성하세요', + checkUpdate: '업데이트 확인', + checkUpdateBtn: '확인', + checkingUpdate: '확인 중…', + upToDate: '현재 최신 버전입니다.', + updateError: '확인 또는 업데이트에 실패했습니다. 잠시 후 다시 시도하세요.', + openReleases: 'Releases 열기', + source: '소스', + docs: '문서', + feedback: '피드백', + qq: '커뮤니티 QQ 그룹', + qqDesc: 'QQ 에서 그룹 번호를 검색해 가입하거나 QR 코드로 입장하세요.', + 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: { - ...en.modal, + sections: { + account: '계정', + settings: '설정', + personalize: '개인 설정', + about: '정보', + helpCenter: '도움말 센터', + releaseNotes: '릴리스 노트', + }, + account: { + localUser: '로컬 사용자', + localUserDesc: '로그인하지 않음 · 모든 데이터는 로컬에 저장', + loginSync: '로그인 / 동기화', + footer: 'OpenLess 는 기본적으로 완전히 로컬에서 동작합니다. 로그인 시 여러 기기 간에 어휘와 스타일 프리셋을 동기화할 수 있으며, 인식은 본 기기 또는 설정한 공급자에서 수행됩니다.', + }, personalize: { - ...en.modal.personalize, + appearance: '모양', + appearanceDesc: '시스템 따라가기 / 라이트 / 다크', + appearanceSystem: '시스템 따라가기', + appearanceLight: '라이트', + appearanceDark: '다크', language: '인터페이스 언어', + font: '글꼴 크기', + fontDesc: 'UI 글꼴 크기를 전체 스케일. 즉시 반영.', + 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 저수준 키보드 후크', + rdev: 'rdev 리스너', + }, + }, + localAsr: { + kicker: '로컬 ASR', + title: '모델 설정', + desc: '로컬 Qwen3-ASR 엔진과 모델 관리. HuggingFace 에서 본 기기로 모델을 다운로드하면 네트워크 없이 인식 가능. Windows 의 스트리밍 추론은 저장소 issue 참조.', + engineUnavailable: '현재 플랫폼은 로컬 추론 엔진이 통합되지 않았습니다(macOS 만 지원, Windows 는 issue #256 추적). 모델은 다운로드 가능하지만 일시적으로 활성화할 수 없습니다.', + mirrorLabel: '다운로드 미러', + mirrorDesc: '공식 소스는 해외 네트워크에서 안정적; hf-mirror.com 은 중국 커뮤니티가 운영하는 미러.', + mirrorHuggingface: 'HuggingFace 공식 (huggingface.co)', + mirrorHfMirror: '중국 미러 (hf-mirror.com)', + activeBadge: '사용 중', + downloadedBadge: '다운로드됨', + download: '다운로드', + resume: '계속 다운로드', + cancel: '취소', + delete: '삭제', + setActive: '기본으로 설정', + failed: '실패', + cancelled: '취소됨', + files: '파일', + sizeLoading: '크기 조회 중…', + sizeUnknown: '크기 알 수 없음', + performanceWarning: '로컬 추론은 CPU + Apple Silicon Accelerate 에서 동작합니다. **첫 전사는 모델 로드(몇 초)가 필요**, 이후 한 번의 전사도 클라우드 ASR 보다 몇 초 느립니다. 중국어 인식 정확도와 방언/억양 대응도 일반적으로 Volcengine / Whisper turbo 에 미치지 못합니다. 적용 시나리오: 오프라인 / 프라이버시 중시 / 클라우드 API 비용을 피하고 싶을 때.', + test: '로드하여 테스트', + testRunning: '테스트 중…', + testHeading: '내장 오디오 테스트', + testExpected: '원문', + testActual: '인식', + testStats: '오디오 길이 {{audio}}s · 로드 {{load}}s · 추론 {{transcribe}}s · 백엔드 {{backend}}', + testFailed: '테스트 실패', + engineStatusLabel: '메모리에 있는 엔진', + engineLoaded: '로드됨: {{model}}(약 1.2-3.4 GB 메모리 사용)', + engineUnloaded: '로드되지 않음(첫 받아쓰기 시 약 3-5 초 로드 필요)', + loadNow: '지금 로드', + releaseNow: '지금 해제', + keepLoadedLabel: '로드 유지 시간', + keepLoadedDesc: '로컬 ASR 사용 후 메모리에서 해제되기까지의 시간을 결정. 1+ GB RAM 장기 점유 회피.', + keepImmediate: '말하기 직후 해제', + keep1min: '마지막 사용 후 1분', + keep5min: '마지막 사용 후 5분(기본)', + keep30min: '마지막 사용 후 30분', + keepForever: '해제하지 않음(항상 유지)', }, }; diff --git a/openless-all/app/src/i18n/zh-CN.ts b/openless-all/app/src/i18n/zh-CN.ts index 93743926..041c46e6 100644 --- a/openless-all/app/src/i18n/zh-CN.ts +++ b/openless-all/app/src/i18n/zh-CN.ts @@ -403,8 +403,8 @@ export const zhCN = { zh: '简体中文', zhTW: '繁體中文', en: 'English', - ja: '日本語', - ko: '한국어', + ja: '日本語 (Beta)', + ko: '한국어 (Beta)', restartHint: '部分原生菜单(系统托盘等)可能需要重启 App 才会切换。', }, about: { diff --git a/openless-all/app/src/i18n/zh-TW.ts b/openless-all/app/src/i18n/zh-TW.ts index 63b0ca84..794a2095 100644 --- a/openless-all/app/src/i18n/zh-TW.ts +++ b/openless-all/app/src/i18n/zh-TW.ts @@ -405,8 +405,8 @@ export const zhTW: typeof zhCN = { zh: '簡體中文', zhTW: '繁體中文', en: 'English', - ja: '日本語', - ko: '한국어', + ja: '日本語 (Beta)', + ko: '한국어 (Beta)', restartHint: '部分原生菜單(系統托盤等)可能需要重啓 App 纔會切換。', }, about: {