diff --git a/src-tauri/src/settings.rs b/src-tauri/src/settings.rs index 878d5a98e..420d0f289 100644 --- a/src-tauri/src/settings.rs +++ b/src-tauri/src/settings.rs @@ -168,6 +168,7 @@ pub enum RecordingRetentionPeriod { pub enum KeyboardImplementation { Tauri, HandyKeys, + None, } impl Default for KeyboardImplementation { @@ -986,4 +987,38 @@ mod tests { assert!(!out.contains("secret")); assert!(out.contains("[REDACTED]")); } + + /// Serialize default settings, apply a JSON override, and deserialize back. + /// This mirrors real-world settings persistence where missing fields get defaults. + fn settings_with_keyboard_override(override_json: &str) -> AppSettings { + let defaults = get_default_settings(); + let mut value: serde_json::Value = serde_json::to_value(&defaults).unwrap(); + let overrides: serde_json::Value = serde_json::from_str(override_json).unwrap(); + if let (serde_json::Value::Object(ref mut map), serde_json::Value::Object(ovr)) = + (&mut value, overrides) + { + for (k, v) in ovr { + map.insert(k, v); + } + } + serde_json::from_value(value).unwrap() + } + + #[test] + fn keyboard_implementation_none_deserializes() { + let settings = settings_with_keyboard_override(r#"{"keyboard_implementation": "none"}"#); + assert_eq!( + settings.keyboard_implementation, + KeyboardImplementation::None + ); + } + + #[test] + fn keyboard_implementation_default_is_not_none() { + let settings = get_default_settings(); + assert_ne!( + settings.keyboard_implementation, + KeyboardImplementation::None + ); + } } diff --git a/src-tauri/src/shortcut/mod.rs b/src-tauri/src/shortcut/mod.rs index 79e0766e3..24478c888 100644 --- a/src-tauri/src/shortcut/mod.rs +++ b/src-tauri/src/shortcut/mod.rs @@ -53,6 +53,9 @@ pub fn init_shortcuts(app: &AppHandle) { tauri_impl::init_shortcuts(app); } } + KeyboardImplementation::None => { + info!("Keyboard shortcuts disabled — use compositor keybindings with --toggle-transcription"); + } } } @@ -62,6 +65,7 @@ pub fn register_cancel_shortcut(app: &AppHandle) { match settings.keyboard_implementation { KeyboardImplementation::Tauri => tauri_impl::register_cancel_shortcut(app), KeyboardImplementation::HandyKeys => handy_keys::register_cancel_shortcut(app), + KeyboardImplementation::None => {} } } @@ -71,6 +75,7 @@ pub fn unregister_cancel_shortcut(app: &AppHandle) { match settings.keyboard_implementation { KeyboardImplementation::Tauri => tauri_impl::unregister_cancel_shortcut(app), KeyboardImplementation::HandyKeys => handy_keys::unregister_cancel_shortcut(app), + KeyboardImplementation::None => {} } } @@ -80,6 +85,7 @@ pub fn register_shortcut(app: &AppHandle, binding: ShortcutBinding) -> Result<() match settings.keyboard_implementation { KeyboardImplementation::Tauri => tauri_impl::register_shortcut(app, binding), KeyboardImplementation::HandyKeys => handy_keys::register_shortcut(app, binding), + KeyboardImplementation::None => Ok(()), } } @@ -89,6 +95,7 @@ pub fn unregister_shortcut(app: &AppHandle, binding: ShortcutBinding) -> Result< match settings.keyboard_implementation { KeyboardImplementation::Tauri => tauri_impl::unregister_shortcut(app, binding), KeyboardImplementation::HandyKeys => handy_keys::unregister_shortcut(app, binding), + KeyboardImplementation::None => Ok(()), } } @@ -322,6 +329,7 @@ pub fn get_keyboard_implementation(app: AppHandle) -> String { match settings.keyboard_implementation { KeyboardImplementation::Tauri => "tauri".to_string(), KeyboardImplementation::HandyKeys => "handy_keys".to_string(), + KeyboardImplementation::None => "none".to_string(), } } @@ -337,6 +345,7 @@ fn validate_shortcut_for_implementation( match implementation { KeyboardImplementation::Tauri => tauri_impl::validate_shortcut(raw), KeyboardImplementation::HandyKeys => handy_keys::validate_shortcut(raw), + KeyboardImplementation::None => Ok(()), } } @@ -345,6 +354,7 @@ fn parse_keyboard_implementation(s: &str) -> KeyboardImplementation { match s { "tauri" => KeyboardImplementation::Tauri, "handy_keys" => KeyboardImplementation::HandyKeys, + "none" => KeyboardImplementation::None, other => { warn!( "Invalid keyboard implementation '{}', defaulting to tauri", @@ -368,6 +378,7 @@ fn unregister_all_shortcuts(app: &AppHandle, implementation: KeyboardImplementat let result = match implementation { KeyboardImplementation::Tauri => tauri_impl::unregister_shortcut(app, binding), KeyboardImplementation::HandyKeys => handy_keys::unregister_shortcut(app, binding), + KeyboardImplementation::None => Ok(()), }; if let Err(e) = result { @@ -426,6 +437,7 @@ fn register_all_shortcuts_for_implementation( let result = match implementation { KeyboardImplementation::Tauri => tauri_impl::register_shortcut(app, binding), KeyboardImplementation::HandyKeys => handy_keys::register_shortcut(app, binding), + KeyboardImplementation::None => Ok(()), }; if let Err(e) = result { @@ -1155,3 +1167,40 @@ pub async fn get_available_accelerators() -> crate::managers::transcription::Ava .await .expect("get_available_accelerators panicked") } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_keyboard_implementation_none() { + assert_eq!( + parse_keyboard_implementation("none"), + KeyboardImplementation::None + ); + } + + #[test] + fn parse_keyboard_implementation_tauri() { + assert_eq!( + parse_keyboard_implementation("tauri"), + KeyboardImplementation::Tauri + ); + } + + #[test] + fn parse_keyboard_implementation_handy_keys() { + assert_eq!( + parse_keyboard_implementation("handy_keys"), + KeyboardImplementation::HandyKeys + ); + } + + #[test] + fn parse_keyboard_implementation_invalid_defaults_to_tauri() { + assert_eq!( + parse_keyboard_implementation("garbage"), + KeyboardImplementation::Tauri + ); + } +} diff --git a/src/bindings.ts b/src/bindings.ts index 476c41180..9c5d34d04 100644 --- a/src/bindings.ts +++ b/src/bindings.ts @@ -851,7 +851,7 @@ export type ImplementationChangeResult = { success: boolean; * List of binding IDs that were reset to defaults due to incompatibility */ reset_bindings: string[] } -export type KeyboardImplementation = "tauri" | "handy_keys" +export type KeyboardImplementation = "tauri" | "handy_keys" | "none" export type LLMPrompt = { id: string; name: string; prompt: string } export type LogLevel = "trace" | "debug" | "info" | "warn" | "error" export type ModelInfo = { id: string; name: string; description: string; filename: string; url: string | null; sha256: string | null; size_mb: number; is_downloaded: boolean; is_downloading: boolean; partial_size: number; is_directory: boolean; engine_type: EngineType; accuracy_score: number; speed_score: number; supports_translation: boolean; is_recommended: boolean; supported_languages: string[]; supports_language_selection: boolean; is_custom: boolean } diff --git a/src/components/settings/debug/KeyboardImplementationSelector.tsx b/src/components/settings/debug/KeyboardImplementationSelector.tsx index f992b639d..c35f3163b 100644 --- a/src/components/settings/debug/KeyboardImplementationSelector.tsx +++ b/src/components/settings/debug/KeyboardImplementationSelector.tsx @@ -1,14 +1,23 @@ import React from "react"; import { useTranslation } from "react-i18next"; +import { type } from "@tauri-apps/plugin-os"; import { SettingContainer } from "../../ui/SettingContainer"; import { Dropdown, type DropdownOption } from "../../ui/Dropdown"; import { useSettings } from "../../../hooks/useSettings"; import { commands } from "@/bindings"; import { toast } from "sonner"; +// "None" is Linux-only: Tauri + Handy Keys both work reliably on macOS and Windows, +// so exposing an option that disables all built-in hotkeys there would be a footgun. +// On Linux (particularly Wayland) the compositor-keybind workflow is a legitimate fallback. +const isLinux = type() === "linux"; + const KEYBOARD_IMPLEMENTATION_OPTIONS: DropdownOption[] = [ { value: "tauri", label: "Tauri Global Shortcut" }, { value: "handy_keys", label: "Handy Keys" }, + ...(isLinux + ? [{ value: "none", label: "None (Compositor Only)" } as DropdownOption] + : []), ]; interface KeyboardImplementationSelectorProps { diff --git a/src/components/settings/general/GeneralSettings.tsx b/src/components/settings/general/GeneralSettings.tsx index adbb6787d..8e3c33b8e 100644 --- a/src/components/settings/general/GeneralSettings.tsx +++ b/src/components/settings/general/GeneralSettings.tsx @@ -16,17 +16,27 @@ export const GeneralSettings: React.FC = () => { const { t } = useTranslation(); const { audioFeedbackEnabled, getSetting } = useSettings(); const pushToTalk = getSetting("push_to_talk"); + const keyboardImpl = getSetting("keyboard_implementation") ?? "tauri"; + const shortcutsDisabled = keyboardImpl === "none"; const isLinux = type() === "linux"; return (
- - - - {/* Cancel shortcut is hidden with push-to-talk (release key cancels) and on Linux (dynamic shortcut instability) */} - {!isLinux && !pushToTalk && ( - - )} - + {shortcutsDisabled ? ( + +
+ {t("settings.general.shortcutsDisabledHint")} +
+
+ ) : ( + + + + {/* Cancel shortcut is hidden with push-to-talk (release key cancels) and on Linux (dynamic shortcut instability) */} + {!isLinux && !pushToTalk && ( + + )} + + )} diff --git a/src/i18n/locales/ar/translation.json b/src/i18n/locales/ar/translation.json index 81f7a14ec..2f65ea771 100644 --- a/src/i18n/locales/ar/translation.json +++ b/src/i18n/locales/ar/translation.json @@ -191,7 +191,8 @@ "pushToTalk": { "label": "اضغط للتحدث", "description": "استمر في الضغط للتسجيل، واترك للتوقف" - } + }, + "shortcutsDisabledHint": "مفاتيح الاختصار المدمجة معطلة. قم بتكوين مدير النوافذ لتشغيل 'handy --toggle-transcription' عند ضغطة مفتاح بدلاً من ذلك (مثال على Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). يمكنك تغيير هذا في الإعدادات > متقدم > تجريبي > تنفيذ لوحة المفاتيح." }, "sound": { "title": "الصوت", diff --git a/src/i18n/locales/bg/translation.json b/src/i18n/locales/bg/translation.json index 2cb5d79dc..b98c76ba7 100644 --- a/src/i18n/locales/bg/translation.json +++ b/src/i18n/locales/bg/translation.json @@ -195,7 +195,8 @@ "pushToTalk": { "label": "Натискане за говорене", "description": "Задръжте за запис, пуснете за спиране" - } + }, + "shortcutsDisabledHint": "Вградените клавишни комбинации са изключени. Конфигурирайте вашия композитор да стартира 'handy --toggle-transcription' с клавишна комбинация (напр. Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Можете да промените това в Настройки > Разширени > Експериментални > Реализация на клавиатурата." }, "models": { "title": "Модели за транскрипция", diff --git a/src/i18n/locales/cs/translation.json b/src/i18n/locales/cs/translation.json index aa93251c5..d3cfcf4e0 100644 --- a/src/i18n/locales/cs/translation.json +++ b/src/i18n/locales/cs/translation.json @@ -213,7 +213,8 @@ "pushToTalk": { "label": "Stisk a mluv", "description": "Podržte pro nahrávání, uvolněte pro zastavení" - } + }, + "shortcutsDisabledHint": "Vestavěné klávesové zkratky jsou zakázány. Místo toho nakonfigurujte kompozitor, aby spouštěl 'handy --toggle-transcription' na klávesovou zkratku (např. Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Toto můžete změnit v Nastavení > Pokročilé > Experimentální > Implementace klávesnice." }, "sound": { "title": "Zvuk", diff --git a/src/i18n/locales/de/translation.json b/src/i18n/locales/de/translation.json index c031bea6d..e7aa1d3d7 100644 --- a/src/i18n/locales/de/translation.json +++ b/src/i18n/locales/de/translation.json @@ -213,7 +213,8 @@ "pushToTalk": { "label": "Push-to-Talk", "description": "Gedrückt halten zum Aufnehmen, loslassen zum Stoppen" - } + }, + "shortcutsDisabledHint": "Integrierte Tastenkombinationen sind deaktiviert. Konfiguriere stattdessen deinen Compositor, um 'handy --toggle-transcription' über eine Tastenkombination auszuführen (z. B. Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Du kannst dies unter Einstellungen > Erweitert > Experimentell > Tastatur-Implementierung ändern." }, "sound": { "title": "Ton", diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index eef96e5be..fa723b5ca 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -157,6 +157,7 @@ }, "general": { "title": "General", + "shortcutsDisabledHint": "Built-in hotkeys are disabled. Configure your compositor to run 'handy --toggle-transcription' on a keybind instead (e.g. Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). You can change this in Settings > Advanced > Experimental > Keyboard Implementation.", "shortcut": { "title": "Handy Shortcuts", "description": "Configure keyboard shortcuts to trigger speech-to-text recording", @@ -492,7 +493,7 @@ }, "keyboardImplementation": { "title": "Keyboard Implementation", - "description": "Choose the keyboard shortcut backend.", + "description": "Choose the keyboard shortcut backend. Select 'None' on Wayland to disable built-in hotkeys and use compositor keybindings instead (e.g. handy --toggle-transcription).", "bindingsReset": "Keyboard shortcuts were incompatible and reset to defaults" }, "paths": { diff --git a/src/i18n/locales/es/translation.json b/src/i18n/locales/es/translation.json index e33d5cb41..49d7adcf1 100644 --- a/src/i18n/locales/es/translation.json +++ b/src/i18n/locales/es/translation.json @@ -213,7 +213,8 @@ "pushToTalk": { "label": "Presionar para Hablar", "description": "Mantén presionado para grabar, suelta para detener" - } + }, + "shortcutsDisabledHint": "Los atajos de teclado integrados están desactivados. Configura tu compositor para ejecutar 'handy --toggle-transcription' con una combinación de teclas (p. ej. Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Puedes cambiar esto en Ajustes > Avanzado > Experimental > Implementación del teclado." }, "sound": { "title": "Sonido", diff --git a/src/i18n/locales/fr/translation.json b/src/i18n/locales/fr/translation.json index 479d00c49..862b7478d 100644 --- a/src/i18n/locales/fr/translation.json +++ b/src/i18n/locales/fr/translation.json @@ -213,7 +213,8 @@ "pushToTalk": { "label": "Appuyer pour parler", "description": "Maintenez pour enregistrer, relâchez pour arrêter" - } + }, + "shortcutsDisabledHint": "Les raccourcis clavier intégrés sont désactivés. Configurez plutôt votre compositeur pour exécuter 'handy --toggle-transcription' sur une combinaison de touches (par exemple Hyprland : bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Vous pouvez modifier ceci dans Paramètres > Avancé > Expérimental > Gestion du clavier." }, "sound": { "title": "Son", diff --git a/src/i18n/locales/he/translation.json b/src/i18n/locales/he/translation.json index 9b0518d39..16e1e2bca 100644 --- a/src/i18n/locales/he/translation.json +++ b/src/i18n/locales/he/translation.json @@ -195,7 +195,8 @@ "pushToTalk": { "label": "לחץ כדי לדבר", "description": "החזק כדי להקליט, שחרר כדי לעצור" - } + }, + "shortcutsDisabledHint": "מקשי קיצור מובנים מושבתים. הגדר את מנהל החלונות שלך להפעיל 'handy --toggle-transcription' באמצעות צירוף מקשים במקום (למשל Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). ניתן לשנות זאת בהגדרות > מתקדם > ניסיוני > מימוש מקלדת." }, "models": { "title": "מודלי תמלול", diff --git a/src/i18n/locales/it/translation.json b/src/i18n/locales/it/translation.json index 6f7cd035e..16d62aa10 100644 --- a/src/i18n/locales/it/translation.json +++ b/src/i18n/locales/it/translation.json @@ -213,7 +213,8 @@ "pushToTalk": { "label": "Premi per Parlare", "description": "Tieni premuto per parlare, rilascia per interrompere" - } + }, + "shortcutsDisabledHint": "Le scorciatoie da tastiera integrate sono disabilitate. Configura invece il tuo compositor per eseguire 'handy --toggle-transcription' con una combinazione di tasti (es. Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Puoi modificarlo in Impostazioni > Avanzate > Sperimentale > Implementazione tastiera." }, "sound": { "title": "Suono", diff --git a/src/i18n/locales/ja/translation.json b/src/i18n/locales/ja/translation.json index a9aad4ed4..37a962c1e 100644 --- a/src/i18n/locales/ja/translation.json +++ b/src/i18n/locales/ja/translation.json @@ -213,7 +213,8 @@ "pushToTalk": { "label": "プッシュトゥトーク", "description": "押し続けて録音、離して停止" - } + }, + "shortcutsDisabledHint": "内蔵のホットキーは無効化されています。代わりにコンポジターを設定して、キーバインドで 'handy --toggle-transcription' を実行してください(例: Hyprland の場合 bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription)。これは 設定 > 詳細設定 > 実験的 > キーボード実装 で変更できます。" }, "sound": { "title": "サウンド", diff --git a/src/i18n/locales/ko/translation.json b/src/i18n/locales/ko/translation.json index 4e168d2b0..59622fe25 100644 --- a/src/i18n/locales/ko/translation.json +++ b/src/i18n/locales/ko/translation.json @@ -195,7 +195,8 @@ "pushToTalk": { "label": "녹음 중 단축키 홀딩", "description": "누르고 있으면 녹음, 놓으면 정지" - } + }, + "shortcutsDisabledHint": "내장 단축키가 비활성화되었습니다. 대신 컴포지터가 키 바인드에서 'handy --toggle-transcription'을 실행하도록 설정하세요 (예: Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). 이는 설정 > 고급 > 실험적 > 키보드 구현에서 변경할 수 있습니다." }, "sound": { "title": "사운드", diff --git a/src/i18n/locales/pl/translation.json b/src/i18n/locales/pl/translation.json index ed064221e..6d7743b01 100644 --- a/src/i18n/locales/pl/translation.json +++ b/src/i18n/locales/pl/translation.json @@ -213,7 +213,8 @@ "pushToTalk": { "label": "Push To Talk", "description": "Przytrzymaj, aby nagrywać, puść, aby zatrzymać" - } + }, + "shortcutsDisabledHint": "Wbudowane skróty klawiszowe są wyłączone. Zamiast tego skonfiguruj swój kompozytor, aby uruchamiał 'handy --toggle-transcription' pod skrótem klawiszowym (np. Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Możesz to zmienić w Ustawieniach > Zaawansowane > Eksperymentalne > Implementacja klawiatury." }, "sound": { "title": "Dźwięk", diff --git a/src/i18n/locales/pt/translation.json b/src/i18n/locales/pt/translation.json index a85436f47..d2af3cc08 100644 --- a/src/i18n/locales/pt/translation.json +++ b/src/i18n/locales/pt/translation.json @@ -195,7 +195,8 @@ "pushToTalk": { "label": "Pressionar para Falar", "description": "Segure para gravar, solte para parar" - } + }, + "shortcutsDisabledHint": "As teclas de atalho integradas estão desativadas. Em vez disso, configure seu compositor para executar 'handy --toggle-transcription' em uma combinação de teclas (por ex. Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Você pode alterar isso em Configurações > Avançado > Experimental > Implementação do Teclado." }, "models": { "title": "Modelos de Transcrição", diff --git a/src/i18n/locales/ru/translation.json b/src/i18n/locales/ru/translation.json index b196a329a..1e605482d 100644 --- a/src/i18n/locales/ru/translation.json +++ b/src/i18n/locales/ru/translation.json @@ -213,7 +213,8 @@ "pushToTalk": { "label": "Нажми и говори", "description": "Удерживайте, чтобы записать, отпустите, чтобы остановить" - } + }, + "shortcutsDisabledHint": "Встроенные горячие клавиши отключены. Вместо этого настройте ваш композитор на выполнение 'handy --toggle-transcription' по нажатию клавиш (например, Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Это можно изменить в Настройки > Продвинутые > Экспериментальное > Реализация клавиатуры." }, "sound": { "title": "Звук", diff --git a/src/i18n/locales/sv/translation.json b/src/i18n/locales/sv/translation.json index de731efc5..0dcbdc920 100644 --- a/src/i18n/locales/sv/translation.json +++ b/src/i18n/locales/sv/translation.json @@ -195,7 +195,8 @@ "pushToTalk": { "label": "Tryck för att tala", "description": "Håll ned för att spela in, släpp för att stoppa" - } + }, + "shortcutsDisabledHint": "Inbyggda snabbtangenter är inaktiverade. Konfigurera istället din kompositör att köra 'handy --toggle-transcription' vid en tangentbindning (t.ex. Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Du kan ändra detta i Inställningar > Avancerat > Experimentellt > Tangentbordsimplementering." }, "models": { "title": "Transkriptionsmodeller", diff --git a/src/i18n/locales/tr/translation.json b/src/i18n/locales/tr/translation.json index e4cc4e2e7..2380c1e10 100644 --- a/src/i18n/locales/tr/translation.json +++ b/src/i18n/locales/tr/translation.json @@ -213,7 +213,8 @@ "pushToTalk": { "label": "Bas Konuş", "description": "Kaydetmek için basılı tutun, durdurmak için bırakın" - } + }, + "shortcutsDisabledHint": "Yerleşik kısayol tuşları devre dışı. Bunun yerine birleştiricinizi bir kısayola 'handy --toggle-transcription' çalıştıracak şekilde yapılandırın (örn. Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Bunu Ayarlar > Gelişmiş > Deneysel > Klavye Uygulaması bölümünden değiştirebilirsiniz." }, "sound": { "title": "Ses", diff --git a/src/i18n/locales/uk/translation.json b/src/i18n/locales/uk/translation.json index 825c1ee15..d413e3dec 100644 --- a/src/i18n/locales/uk/translation.json +++ b/src/i18n/locales/uk/translation.json @@ -195,7 +195,8 @@ "pushToTalk": { "label": "Утримувати для запису (Push To Talk)", "description": "Утримуйте для запису, відпустіть для зупинки" - } + }, + "shortcutsDisabledHint": "Вбудовані гарячі клавіші вимкнені. Натомість налаштуйте ваш композитор на запуск 'handy --toggle-transcription' за комбінацією клавіш (наприклад, Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Це можна змінити в Налаштування > Розширені > Експериментальне > Реалізація клавіатури." }, "models": { "title": "Моделі транскрипції", diff --git a/src/i18n/locales/vi/translation.json b/src/i18n/locales/vi/translation.json index b6bfe7c96..968556399 100644 --- a/src/i18n/locales/vi/translation.json +++ b/src/i18n/locales/vi/translation.json @@ -213,7 +213,8 @@ "pushToTalk": { "label": "Nhấn để nói", "description": "Giữ để ghi âm, thả để dừng" - } + }, + "shortcutsDisabledHint": "Phím nóng tích hợp đã bị tắt. Thay vào đó, hãy cấu hình compositor của bạn để chạy 'handy --toggle-transcription' trên một tổ hợp phím (ví dụ Hyprland: bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription). Bạn có thể thay đổi điều này trong Cài đặt > Nâng cao > Thử nghiệm > Triển khai bàn phím." }, "sound": { "title": "Âm thanh", diff --git a/src/i18n/locales/zh-TW/translation.json b/src/i18n/locales/zh-TW/translation.json index 6eee9637a..50921a5d9 100644 --- a/src/i18n/locales/zh-TW/translation.json +++ b/src/i18n/locales/zh-TW/translation.json @@ -195,7 +195,8 @@ "pushToTalk": { "label": "按住說話", "description": "按住錄製,放開停止" - } + }, + "shortcutsDisabledHint": "內建熱鍵已停用。請改為設定合成器在某個鍵位上執行 'handy --toggle-transcription'(例如 Hyprland:bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription)。您可以在 設定 > 進階 > 實驗性 > 鍵盤實作 中變更此設定。" }, "models": { "title": "轉錄模型", diff --git a/src/i18n/locales/zh/translation.json b/src/i18n/locales/zh/translation.json index 7dd690c54..808f74855 100644 --- a/src/i18n/locales/zh/translation.json +++ b/src/i18n/locales/zh/translation.json @@ -213,7 +213,8 @@ "pushToTalk": { "label": "按住说话", "description": "按住录制,松开停止" - } + }, + "shortcutsDisabledHint": "内置热键已禁用。请改为配置合成器在某个键位上运行 'handy --toggle-transcription'(例如 Hyprland:bind = CTRL SHIFT, SPACE, exec, handy --toggle-transcription)。您可以在 设置 > 高级 > 实验性 > 键盘实现 中更改此设置。" }, "sound": { "title": "声音",