fix(i18n,ui): 补 ja/ko 缺失 key + SelectionAsk 启用开关右置
PR #236 合并后两处后续修复: 1. ja.ts / ko.ts 缺 PR 引入的 7 个 comboRecord* 键和 1 个 triggers.custom 键,导致 main 的 npm run build 直接 TS 报错。 补齐后 tsc 通过。 2. SelectionAsk 划词追问页:触发快捷键卡片把"右上角状态徽标 + 下方启用按钮"换成与 Style 页一致的右上角 36×20 toggle; 保存历史卡片同步从底部 44×24 开关改成右上角同款 toggle。 抽出 CardHeaderToggle 复用,跟 design_handoff Style 页对齐。
This commit is contained in:
1 parent
98da5970bf
commit
1e04433443
3 files changed
+76
-56
No files matched your search
@@ -282,6 +282,13 @@ export const ja: typeof zhCN = {
|
||||
muteDuringRecordingDesc: '音声入力開始時にシステム出力を一時的にミュートし、停止/キャンセル/エラー後に元のミュート状態を復元。スピーカーの音がマイクに入らないようにします。',
|
||||
restoreClipboardLabel: '入力後にクリップボードを復元',
|
||||
restoreClipboardDesc: 'Windows / Linux のみ:ペースト成功後に元のクリップボード内容を復元(既定 ON)。OFF にするとディクテーションテキストがクリップボードに残り、ペーストが効かなかった場合に手動で Ctrl+V できます。詳細は issue #111。',
|
||||
comboRecordLabel: 'ショートカットを記録',
|
||||
comboRecordDesc: 'クリック後、希望するキーの組み合わせ(例:⌘⇧D)を押してください。トグル / 押し続けの両方に対応。',
|
||||
comboRecordBtn: 'ショートカットを記録',
|
||||
comboRecordHint: 'ショートカットの組み合わせを押してください…',
|
||||
comboRecorded: '記録済み',
|
||||
comboClear: 'クリア',
|
||||
comboConflict: 'このショートカットの組み合わせは使用できません',
|
||||
allowNonTsfFallbackLabel: '非 TSF フォールバックを許可',
|
||||
allowNonTsfFallbackDesc: 'Windows のみ:TSF による直接入力が失敗した場合、Unicode SendInput / ショートカットペースト / WM_PASTE への切り替えを許可。OFF にすると TSF 入力が実際に使われているか検証できます。',
|
||||
startupAtBoot: '起動時に自動起動',
|
||||
@@ -527,6 +534,7 @@ export const ja: typeof zhCN = {
|
||||
rightCommand: '右 Command',
|
||||
fn: 'Fn (地球キー)',
|
||||
rightAlt: '右 Alt',
|
||||
custom: 'カスタム',
|
||||
},
|
||||
fallback: 'グローバルショートカット',
|
||||
modeHoldSuffix: '(押し続けて話す)',
|
||||
|
||||
@@ -282,6 +282,13 @@ export const ko: typeof zhCN = {
|
||||
muteDuringRecordingDesc: '음성 입력 시작 시 시스템 출력을 일시적으로 음소거하고, 정지/취소/오류 후 원래 음소거 상태를 복원합니다. 스피커 소리가 마이크에 들어가지 않도록 합니다.',
|
||||
restoreClipboardLabel: '입력 후 클립보드 복원',
|
||||
restoreClipboardDesc: 'Windows / Linux 만: 붙여넣기 성공 후 원래 클립보드 내용을 복원합니다(기본 ON). OFF 시 받아쓰기 텍스트가 클립보드에 남아 붙여넣기가 실패한 경우 수동으로 Ctrl+V 할 수 있습니다. issue #111 참조.',
|
||||
comboRecordLabel: '단축키 녹화',
|
||||
comboRecordDesc: '클릭 후 원하는 단축키 조합(예: ⌘⇧D)을 누르세요. 토글 및 누르기 모드 모두 지원합니다.',
|
||||
comboRecordBtn: '단축키 녹화',
|
||||
comboRecordHint: '단축키 조합을 눌러 주세요…',
|
||||
comboRecorded: '녹화됨',
|
||||
comboClear: '지우기',
|
||||
comboConflict: '이 단축키 조합은 사용할 수 없습니다',
|
||||
allowNonTsfFallbackLabel: '비 TSF 폴백 허용',
|
||||
allowNonTsfFallbackDesc: 'Windows 만: TSF 직접 입력이 실패할 경우 Unicode SendInput / 단축키 붙여넣기 / WM_PASTE 로 전환을 허용합니다. OFF 시 실제로 TSF 입력이 사용되는지 검증할 수 있습니다.',
|
||||
startupAtBoot: '부팅 시 자동 시작',
|
||||
@@ -527,6 +534,7 @@ export const ko: typeof zhCN = {
|
||||
rightCommand: '오른쪽 Command',
|
||||
fn: 'Fn (지구본 키)',
|
||||
rightAlt: '오른쪽 Alt',
|
||||
custom: '사용자 정의',
|
||||
},
|
||||
fallback: '전역 단축키',
|
||||
modeHoldSuffix: '(눌러서 말하기)',
|
||||
|
||||
@@ -58,36 +58,18 @@ export function SelectionAsk() {
|
||||
|
||||
{/* 1. 触发快捷键 */}
|
||||
<Card>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 4 }}>
|
||||
<div style={{ fontSize: 13, fontWeight: 600 }}>{t('selectionAsk.hotkey.title')}</div>
|
||||
<span
|
||||
style={{
|
||||
padding: '2px 8px',
|
||||
fontSize: 10.5,
|
||||
fontWeight: 600,
|
||||
letterSpacing: '0.04em',
|
||||
borderRadius: 999,
|
||||
background: enabled ? 'rgba(37,99,235,0.10)' : 'rgba(0,0,0,0.05)',
|
||||
color: enabled ? 'var(--ol-blue)' : 'var(--ol-ink-4)',
|
||||
textTransform: 'uppercase',
|
||||
}}
|
||||
>
|
||||
{enabled ? t('selectionAsk.statusEnabled') : t('selectionAsk.statusDisabled')}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ fontSize: 11.5, color: 'var(--ol-ink-4)', marginBottom: 12, lineHeight: 1.55 }}>
|
||||
{t('selectionAsk.hotkey.desc', { recordHotkey: recordHotkeyLabel })}
|
||||
</div>
|
||||
<button
|
||||
onClick={async () => {
|
||||
<CardHeaderToggle
|
||||
title={t('selectionAsk.hotkey.title')}
|
||||
checked={enabled}
|
||||
onToggle={async () => {
|
||||
const nextHotkey = enabled ? null : defaultQaHotkey;
|
||||
await setQaHotkey(nextHotkey);
|
||||
await savePrefs({ ...prefs, qaHotkey: nextHotkey });
|
||||
}}
|
||||
style={{ fontSize: 12, padding: '5px 14px', background: enabled ? 'rgba(0,0,0,0.06)' : 'var(--ol-blue)', color: enabled ? 'var(--ol-ink-2)' : '#fff', border: 0, borderRadius: 6, fontFamily: 'inherit', fontWeight: 500, cursor: 'default', marginBottom: 10 }}
|
||||
>
|
||||
{enabled ? t('selectionAsk.hotkey.optionDisabled') : t('selectionAsk.statusEnabled')}
|
||||
</button>
|
||||
/>
|
||||
<div style={{ fontSize: 11.5, color: 'var(--ol-ink-4)', marginBottom: prefs.qaHotkey ? 12 : 0, lineHeight: 1.55 }}>
|
||||
{t('selectionAsk.hotkey.desc', { recordHotkey: recordHotkeyLabel })}
|
||||
</div>
|
||||
{prefs.qaHotkey && (
|
||||
<ShortcutRecorder
|
||||
value={prefs.qaHotkey}
|
||||
@@ -101,38 +83,14 @@ export function SelectionAsk() {
|
||||
|
||||
{/* 2. 历史保存 */}
|
||||
<Card>
|
||||
<div style={{ fontSize: 13, fontWeight: 600, marginBottom: 4 }}>{t('selectionAsk.history.title')}</div>
|
||||
<div style={{ fontSize: 11.5, color: 'var(--ol-ink-4)', marginBottom: 12, lineHeight: 1.55 }}>
|
||||
<CardHeaderToggle
|
||||
title={t('selectionAsk.history.title')}
|
||||
checked={prefs.qaSaveHistory}
|
||||
onToggle={() => onSaveHistoryChange(!prefs.qaSaveHistory)}
|
||||
/>
|
||||
<div style={{ fontSize: 11.5, color: 'var(--ol-ink-4)', lineHeight: 1.55 }}>
|
||||
{t('selectionAsk.history.desc')}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => onSaveHistoryChange(!prefs.qaSaveHistory)}
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: 44,
|
||||
height: 24,
|
||||
borderRadius: 999,
|
||||
border: 0,
|
||||
background: prefs.qaSaveHistory ? 'var(--ol-blue)' : 'rgba(0,0,0,0.18)',
|
||||
cursor: 'default',
|
||||
transition: 'background 0.16s var(--ol-motion-quick)',
|
||||
padding: 0,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 2,
|
||||
left: prefs.qaSaveHistory ? 22 : 2,
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: 999,
|
||||
background: '#fff',
|
||||
boxShadow: '0 1px 2px rgba(0,0,0,.18)',
|
||||
transition: 'left .16s var(--ol-motion-spring)',
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
</Card>
|
||||
|
||||
{/* 3. 使用方法 */}
|
||||
@@ -181,3 +139,49 @@ export function SelectionAsk() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// 卡片标题行右侧开关:与 Style 页面顶栏的 36×20 toggle 同款,保持全局视觉一致。
|
||||
function CardHeaderToggle({
|
||||
title,
|
||||
checked,
|
||||
onToggle,
|
||||
}: {
|
||||
title: string;
|
||||
checked: boolean;
|
||||
onToggle: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 6 }}>
|
||||
<div style={{ fontSize: 13, fontWeight: 600 }}>{title}</div>
|
||||
<button
|
||||
onClick={onToggle}
|
||||
aria-pressed={checked}
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: 36,
|
||||
height: 20,
|
||||
borderRadius: 999,
|
||||
border: 0,
|
||||
background: checked ? 'var(--ol-blue)' : 'rgba(0,0,0,0.15)',
|
||||
cursor: 'default',
|
||||
transition: 'background 0.16s var(--ol-motion-quick)',
|
||||
padding: 0,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 2,
|
||||
left: checked ? 18 : 2,
|
||||
width: 16,
|
||||
height: 16,
|
||||
borderRadius: 999,
|
||||
background: '#fff',
|
||||
boxShadow: '0 1px 2px rgba(0,0,0,.2)',
|
||||
transition: 'left .16s var(--ol-motion-spring)',
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user