diff --git a/src/AppDelegate.swift b/src/AppDelegate.swift index cffe7b3..6cfe021 100644 --- a/src/AppDelegate.swift +++ b/src/AppDelegate.swift @@ -54,7 +54,11 @@ public final class AppDelegate: NSObject, NSApplicationDelegate { } } + // Initial Hotkey Registration (immediate and deferred for AX permission readiness) HotkeyManager.shared.registerHotkeys() + DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { + HotkeyManager.shared.registerHotkeys() + } // Listen to live audio levels & update HUD audioRecorder.onAudioLevelUpdate = { [weak self] level in diff --git a/src/SonioxClient.swift b/src/SonioxClient.swift index 84aec50..08ca4db 100644 --- a/src/SonioxClient.swift +++ b/src/SonioxClient.swift @@ -86,10 +86,18 @@ public final class SonioxLiveSession { self.targetLanguage = effectiveTarget let hints = languageHints.map { "language_hints=\($0)" }.joined(separator: "&") - var urlStr = "\(endpoint)?\(hints)&enable_speaker_diarization=false&enable_language_identification=true&enable_endpoint_detection=false&providers=soniox" + var queryParams: [String] = [] + if !hints.isEmpty { + queryParams.append(hints) + } + queryParams.append("enable_speaker_diarization=false") + queryParams.append("enable_language_identification=true") + queryParams.append("enable_endpoint_detection=false") + queryParams.append("providers=soniox") if let target = effectiveTarget, !target.isEmpty, target != "off" { - urlStr += "&target_language=\(target)" + queryParams.append("target_language=\(target)") } + let urlStr = "\(endpoint)?" + queryParams.joined(separator: "&") guard let url = URL(string: urlStr) else { return } var request = URLRequest(url: url) @@ -374,10 +382,18 @@ public final class SonioxLiveSession { ) { let isTranslationMode = targetLanguage != nil && !targetLanguage!.isEmpty && targetLanguage != "off" let hints = languageHints.map { "language_hints=\($0)" }.joined(separator: "&") - var urlStr = "\(endpoint)?\(hints)&enable_speaker_diarization=false&enable_language_identification=true&enable_endpoint_detection=false&providers=soniox" + var queryParams: [String] = [] + if !hints.isEmpty { + queryParams.append(hints) + } + queryParams.append("enable_speaker_diarization=false") + queryParams.append("enable_language_identification=true") + queryParams.append("enable_endpoint_detection=false") + queryParams.append("providers=soniox") if let target = targetLanguage, !target.isEmpty, target != "off" { - urlStr += "&target_language=\(target)" + queryParams.append("target_language=\(target)") } + let urlStr = "\(endpoint)?" + queryParams.joined(separator: "&") guard let url = URL(string: urlStr) else { completion(.failure(NSError(domain: "Soniox", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"]))) return diff --git a/src/SonioxSettings.swift b/src/SonioxSettings.swift index 9445b43..faa9faa 100644 --- a/src/SonioxSettings.swift +++ b/src/SonioxSettings.swift @@ -3,33 +3,51 @@ import Cocoa public enum RecognitionLanguage: String, CaseIterable { case multi = "multi" + case all = "all" case persian = "fa" case english = "en" + case arabic = "ar" case persianEnglish = "fa_en" + case persianArabic = "fa_ar" + case persianEnglishArabic = "fa_en_ar" public var displayName: String { switch self { case .multi: return "Multilingual (Persian, English, Arabic)" + case .all: + return "🌍 All Languages (Automatic Full Detection)" case .persian: return "Persian Only (فارسی)" case .english: return "English Only" + case .arabic: + return "Arabic Only (عربی)" case .persianEnglish: return "Persian + English" + case .persianArabic: + return "Persian + Arabic" + case .persianEnglishArabic: + return "Persian + English + Arabic" } } public var hints: [String] { switch self { - case .multi: + case .multi, .persianEnglishArabic: return ["fa", "en", "ar"] + case .all: + return [] // When empty, Soniox auto-identifies all 60+ global languages! case .persian: return ["fa"] case .english: return ["en"] + case .arabic: + return ["ar"] case .persianEnglish: return ["fa", "en"] + case .persianArabic: + return ["fa", "ar"] } } } @@ -108,6 +126,9 @@ public final class SonioxSettings { private let defaults = UserDefaults.standard private init() { + if defaults.object(forKey: "SonioxHotkeyPreset") == nil { + defaults.set(HotkeyPreset.option.rawValue, forKey: "SonioxHotkeyPreset") + } ensureHardwareKeyRemapping() }