| | |
| | | <script lang="ts"> |
| | | import { Call } from '@wailsio/runtime' |
| | | import ToggleSwitch from '../shared/ToggleSwitch.svelte' |
| | | import { t } from '../../lib/i18n' |
| | | import { autoHide, soundFeedback, copyToClipboard, startAtLogin, hotkeyVK, hotkeyMode } from '../../lib/stores/config' |
| | | import { t, setLocale } from '../../lib/i18n' |
| | | import { autoHide, soundFeedback, copyToClipboard, startAtLogin, hotkeyVK, hotkeyMode, languageMode, languageID, effectiveLanguageID, uiLocale } from '../../lib/stores/config' |
| | | import { deviceName, engineStatus, engineHardwareInfo } from '../../lib/stores/app' |
| | | import { hotkeyName } from '../../lib/stores/indicator' |
| | | |
| | |
| | | let hwInfo = $state('') |
| | | let currentKeyName = $state('Ctrl') |
| | | let hotkeyModeVal: 'tap' | 'hold' = $state('hold') |
| | | let languageModeVal: 'auto' | 'manual' = $state('auto') |
| | | let languageIDVal: 'zh-CN' | 'en' = $state('zh-CN') |
| | | let effectiveLanguageIDVal: 'zh-CN' | 'en' = $state('zh-CN') |
| | | let isRecording = $state(false) |
| | | let hintText = $state('') |
| | | let devices = $state<InputDevice[]>([]) |
| | |
| | | const unsub7 = soundFeedback.subscribe(v => { soundFeedbackVal = v }) |
| | | const unsub8 = copyToClipboard.subscribe(v => { copyToClipboardVal = v }) |
| | | const unsub9 = hotkeyMode.subscribe(v => { hotkeyModeVal = v }) |
| | | const unsub10 = languageMode.subscribe(v => { languageModeVal = v }) |
| | | const unsub11 = languageID.subscribe(v => { languageIDVal = v }) |
| | | const unsub12 = effectiveLanguageID.subscribe(v => { effectiveLanguageIDVal = v }) |
| | | |
| | | // Load actual device name from backend on mount |
| | | async function loadDeviceName() { |
| | |
| | | const hideDock: any = await Call.ByName('voicesnap/services.ConfigService.GetHideDockIcon') |
| | | hideDockIconVal = !!hideDock |
| | | } catch {} |
| | | try { |
| | | const lang: any = await Call.ByName('voicesnap/services.ConfigService.GetLanguageSettings') |
| | | applyLanguageSettings(lang) |
| | | } catch {} |
| | | settingsLoaded = true |
| | | } |
| | | loadSettings() |
| | | |
| | | function applyLanguageSettings(settings: any) { |
| | | const mode = settings?.languageMode === 'manual' ? 'manual' : 'auto' |
| | | const configured = settings?.languageID === 'en' ? 'en' : 'zh-CN' |
| | | const effective = settings?.effectiveLanguageID === 'en' ? 'en' : 'zh-CN' |
| | | const locale = settings?.uiLocale === 'en' ? 'en' : 'zh' |
| | | languageMode.set(mode) |
| | | languageID.set(configured) |
| | | effectiveLanguageID.set(effective) |
| | | uiLocale.set(locale) |
| | | languageModeVal = mode |
| | | languageIDVal = configured |
| | | effectiveLanguageIDVal = effective |
| | | setLocale(locale) |
| | | } |
| | | |
| | | async function onAutoHideChange(checked: boolean) { |
| | | autoHide.set(checked) |
| | |
| | | try { |
| | | await Call.ByName('voicesnap/services.ConfigService.SetHotkeyMode', mode) |
| | | } catch {} |
| | | } |
| | | |
| | | async function onLanguageChange(selection: 'auto' | 'zh-CN' | 'en') { |
| | | const prevMode = languageModeVal |
| | | const prevID = languageIDVal |
| | | if (selection === 'auto') { |
| | | languageModeVal = 'auto' |
| | | languageMode.set('auto') |
| | | } else { |
| | | languageModeVal = 'manual' |
| | | languageIDVal = selection |
| | | languageMode.set('manual') |
| | | languageID.set(selection) |
| | | } |
| | | try { |
| | | const settings: any = selection === 'auto' |
| | | ? await Call.ByName('voicesnap/services.ConfigService.SetLanguageAuto') |
| | | : await Call.ByName('voicesnap/services.ConfigService.SetLanguageManual', selection) |
| | | applyLanguageSettings(settings) |
| | | } catch { |
| | | languageModeVal = prevMode |
| | | languageIDVal = prevID |
| | | languageMode.set(prevMode) |
| | | languageID.set(prevID) |
| | | } |
| | | } |
| | | |
| | | async function onStartAtLoginChange(checked: boolean) { |
| | |
| | | </div> |
| | | |
| | | </div> |
| | | |
| | | {#if settingsLoaded} |
| | | <div class="section"> |
| | | <div class="setting-row"> |
| | | <div class="setting-info"> |
| | | <span class="setting-label">{t('settings.language')}</span> |
| | | <span class="setting-desc"> |
| | | {languageModeVal === 'auto' |
| | | ? t('settings.languageAutoDesc') |
| | | : effectiveLanguageIDVal === 'en' |
| | | ? t('settings.languageEnglishDesc') |
| | | : t('settings.languageChineseDesc')} |
| | | </span> |
| | | </div> |
| | | <div class="segmented language" role="group" aria-label={t('settings.language')}> |
| | | <button |
| | | class:active={languageModeVal === 'auto'} |
| | | onclick={() => onLanguageChange('auto')} |
| | | > |
| | | {t('settings.languageAuto')} |
| | | </button> |
| | | <button |
| | | class:active={languageModeVal === 'manual' && languageIDVal === 'zh-CN'} |
| | | onclick={() => onLanguageChange('zh-CN')} |
| | | > |
| | | {t('settings.languageChinese')} |
| | | </button> |
| | | <button |
| | | class:active={languageModeVal === 'manual' && languageIDVal === 'en'} |
| | | onclick={() => onLanguageChange('en')} |
| | | > |
| | | {t('settings.languageEnglish')} |
| | | </button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | {/if} |
| | | |
| | | <!-- Engine + Device --> |
| | | <!-- svelte-ignore a11y_click_events_have_key_events --> |
| | |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .segmented.language { |
| | | grid-template-columns: repeat(3, 1fr); |
| | | min-width: 246px; |
| | | } |
| | | |
| | | .segmented.language button { |
| | | min-width: 76px; |
| | | padding: 0 10px; |
| | | } |
| | | |
| | | .segmented button { |
| | | min-width: 66px; |
| | | height: 30px; |