diff --git a/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx b/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx index b2d055e8..dbd19d6d 100644 --- a/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx +++ b/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx @@ -13,7 +13,11 @@ import { import { useEffect, useMemo, useState } from 'react' import { ConnectionState, RoomEvent } from 'livekit-client' import { useTranslation } from 'react-i18next' -import { RecordingStatus, recordingStore } from '@/stores/recording' +import { + RecordingLanguage, + RecordingStatus, + recordingStore, +} from '@/stores/recording' import { FeatureFlags } from '@/features/analytics/enums' import { NotificationType, @@ -31,6 +35,12 @@ import { LoginButton } from '@/components/LoginButton' import { HStack, VStack } from '@/styled-system/jsx' import { Checkbox } from '@/primitives/Checkbox.tsx' +import { + useSettingsDialog, + SettingsDialogExtendedKey, + useTranscriptionLanguageOptions, +} from '@/features/settings' + export const TranscriptSidePanel = () => { const { data } = useConfig() @@ -45,6 +55,9 @@ export const TranscriptSidePanel = () => { const recordingSnap = useSnapshot(recordingStore) const { notifyParticipants } = useNotifyParticipants() + const languageOptions = useTranscriptionLanguageOptions() + + const { openSettingsDialog } = useSettingsDialog() const hasTranscriptAccess = useHasRecordingAccess( RecordingMode.Transcript, @@ -115,7 +128,9 @@ export const TranscriptSidePanel = () => { : RecordingMode.Transcript const recordingOptions = { - language: 'fr', // fix hardcoded language + ...(recordingSnap.language != RecordingLanguage.AUTOMATIC && { + language: recordingSnap.language, + }), ...(includeScreenRecording && { transcribe: true }), } @@ -459,9 +474,27 @@ export const TranscriptSidePanel = () => {
{t('details.language')} + + +
diff --git a/src/frontend/src/features/settings/components/SettingsDialogExtended.tsx b/src/frontend/src/features/settings/components/SettingsDialogExtended.tsx index 4c646114..64148508 100644 --- a/src/frontend/src/features/settings/components/SettingsDialogExtended.tsx +++ b/src/frontend/src/features/settings/components/SettingsDialogExtended.tsx @@ -16,6 +16,7 @@ import { NotificationsTab } from './tabs/NotificationsTab' import { GeneralTab } from './tabs/GeneralTab' import { AudioTab } from './tabs/AudioTab' import { VideoTab } from './tabs/VideoTab' +import { TranscriptionTab } from './tabs/TranscriptionTab' import { useRef } from 'react' import { useMediaQuery } from '@/features/rooms/livekit/hooks/useMediaQuery' import { SettingsDialogExtendedKey } from '@/features/settings/type' @@ -100,6 +101,11 @@ export const SettingsDialogExtended = (props: SettingsDialogExtended) => { {isWideScreen && t(`tabs.${SettingsDialogExtendedKey.NOTIFICATIONS}`)} + + speech_to_text + {isWideScreen && + t(`tabs.${SettingsDialogExtendedKey.TRANSCRIPTION}`)} +
@@ -111,6 +117,8 @@ export const SettingsDialogExtended = (props: SettingsDialogExtended) => { + {/* Transcription tab won't be accessible if the tab is not active in the tab list */} +
diff --git a/src/frontend/src/features/settings/components/tabs/TranscriptionTab.tsx b/src/frontend/src/features/settings/components/tabs/TranscriptionTab.tsx new file mode 100644 index 00000000..3e859b0a --- /dev/null +++ b/src/frontend/src/features/settings/components/tabs/TranscriptionTab.tsx @@ -0,0 +1,30 @@ +import { TabPanel, TabPanelProps } from '@/primitives/Tabs' +import { Field, H } from '@/primitives' +import { useTranslation } from 'react-i18next' +import { RecordingLanguage, recordingStore } from '@/stores/recording' +import { useSnapshot } from 'valtio' +import { useTranscriptionLanguageOptions } from '../../hook/useTranscriptionLanguageOptions' + +export type TranscriptionTabProps = Pick + +export const TranscriptionTab = ({ id }: TranscriptionTabProps) => { + const { t } = useTranslation('settings', { keyPrefix: 'transcription' }) + const recordingSnap = useSnapshot(recordingStore) + + const languageOptions = useTranscriptionLanguageOptions() + + return ( + + {t('heading')} + { + recordingStore.language = lang as RecordingLanguage + }} + /> + + ) +} diff --git a/src/frontend/src/features/settings/hook/useTranscriptionLanguageOptions.ts b/src/frontend/src/features/settings/hook/useTranscriptionLanguageOptions.ts new file mode 100644 index 00000000..f0dfc336 --- /dev/null +++ b/src/frontend/src/features/settings/hook/useTranscriptionLanguageOptions.ts @@ -0,0 +1,28 @@ +import { useMemo } from 'react' +import { RecordingLanguage } from '@/stores/recording' +import { useTranslation } from 'react-i18next' + +export const useTranscriptionLanguageOptions = () => { + const { t } = useTranslation('settings', { keyPrefix: 'transcription' }) + + return useMemo( + () => [ + { + key: RecordingLanguage.FRENCH, + value: RecordingLanguage.FRENCH, + label: t('language.options.french'), + }, + { + key: RecordingLanguage.ENGLISH, + value: RecordingLanguage.ENGLISH, + label: t('language.options.english'), + }, + { + key: RecordingLanguage.AUTOMATIC, + value: RecordingLanguage.AUTOMATIC, + label: t('language.options.auto'), + }, + ], + [t] + ) +} diff --git a/src/frontend/src/features/settings/index.ts b/src/frontend/src/features/settings/index.ts index 077df744..1c198824 100644 --- a/src/frontend/src/features/settings/index.ts +++ b/src/frontend/src/features/settings/index.ts @@ -1,2 +1,7 @@ export { SettingsButton } from './components/SettingsButton' export { SettingsDialog } from './components/SettingsDialog' + +export { useTranscriptionLanguageOptions } from './hook/useTranscriptionLanguageOptions' +export { useSettingsDialog } from './hook/useSettingsDialog' + +export { SettingsDialogExtendedKey } from './type.ts' diff --git a/src/frontend/src/features/settings/type.ts b/src/frontend/src/features/settings/type.ts index e0a39b6d..0a1af14f 100644 --- a/src/frontend/src/features/settings/type.ts +++ b/src/frontend/src/features/settings/type.ts @@ -4,4 +4,5 @@ export enum SettingsDialogExtendedKey { VIDEO = 'video', GENERAL = 'general', NOTIFICATIONS = 'notifications', + TRANSCRIPTION = 'transcription', } diff --git a/src/frontend/src/locales/de/rooms.json b/src/frontend/src/locales/de/rooms.json index f93458ae..c72c1fba 100644 --- a/src/frontend/src/locales/de/rooms.json +++ b/src/frontend/src/locales/de/rooms.json @@ -317,7 +317,7 @@ "receiver": "Das Transkript wird an den Organisator und die Mitorganisatoren gesendet.", "destination": "Ein neues Dokument wird erstellt auf", "destinationUnknown": "Ein neues Dokument wird erstellt", - "language": "Meeting-Sprachen: Französisch (fr)", + "language": "Meeting-Sprache:", "recording": "Auch eine Aufzeichnung starten" }, "button": { diff --git a/src/frontend/src/locales/de/settings.json b/src/frontend/src/locales/de/settings.json index 873b9994..c8a91204 100644 --- a/src/frontend/src/locales/de/settings.json +++ b/src/frontend/src/locales/de/settings.json @@ -68,6 +68,17 @@ }, "permissionsRequired": "Berechtigungen erforderlich" }, + "transcription": { + "heading": "Transkription", + "language": { + "label": "Besprechungssprache", + "options": { + "french": "Französisch (fr)", + "english": "Englisch (en)", + "auto": "Automatisch" + } + } + }, "notifications": { "heading": "Tonbenachrichtigungen", "label": "Tonbenachrichtigungen für", @@ -100,6 +111,7 @@ "audio": "Audio", "video": "Video", "general": "Allgemein", - "notifications": "Benachrichtigungen" + "notifications": "Benachrichtigungen", + "transcription": "Transkription" } } diff --git a/src/frontend/src/locales/en/rooms.json b/src/frontend/src/locales/en/rooms.json index 5eae0399..a58b7154 100644 --- a/src/frontend/src/locales/en/rooms.json +++ b/src/frontend/src/locales/en/rooms.json @@ -317,7 +317,7 @@ "receiver": "The transcript will be sent to the host and co-hosts.", "destination": "A new document will be created on", "destinationUnknown": "A new document will be created", - "language": "Meeting language: French (fr)", + "language": "Meeting language:", "recording": "Also start a recording" }, "button": { diff --git a/src/frontend/src/locales/en/settings.json b/src/frontend/src/locales/en/settings.json index eb7bb294..3deecec1 100644 --- a/src/frontend/src/locales/en/settings.json +++ b/src/frontend/src/locales/en/settings.json @@ -68,6 +68,17 @@ }, "permissionsRequired": "Permissions required" }, + "transcription": { + "heading": "Transcription", + "language": { + "label": "Meeting language", + "options": { + "french": "French (fr)", + "english": "English (en)", + "auto": "Automatic" + } + } + }, "notifications": { "heading": "Sound notifications", "label": "sound notifications for", @@ -100,6 +111,7 @@ "audio": "Audio", "video": "Video", "general": "General", - "notifications": "Notifications" + "notifications": "Notifications", + "transcription": "Transcription" } } diff --git a/src/frontend/src/locales/fr/rooms.json b/src/frontend/src/locales/fr/rooms.json index 56e87e34..c9066505 100644 --- a/src/frontend/src/locales/fr/rooms.json +++ b/src/frontend/src/locales/fr/rooms.json @@ -317,7 +317,7 @@ "receiver": "La transcription sera envoyée à l'organisateur et aux coorganisateurs.", "destination": "Un nouveau document sera créé sur", "destinationUnknown": "Un nouveau document sera créé", - "language": "Langues de la réunion : Français (fr)", + "language": "Langue de la réunion :", "recording": "Démarrer aussi un enregistrement" }, "button": { diff --git a/src/frontend/src/locales/fr/settings.json b/src/frontend/src/locales/fr/settings.json index bc1704e3..53df0074 100644 --- a/src/frontend/src/locales/fr/settings.json +++ b/src/frontend/src/locales/fr/settings.json @@ -68,6 +68,17 @@ }, "permissionsRequired": "Autorisations nécessaires" }, + "transcription": { + "heading": "Transcription", + "language": { + "label": "Langue de la réunion", + "options": { + "french": "Français (fr)", + "english": "Anglais (en)", + "auto": "Automatique" + } + } + }, "notifications": { "heading": "Notifications sonores", "label": "la notification sonore pour", @@ -100,6 +111,7 @@ "audio": "Audio", "video": "Vidéo", "general": "Général", - "notifications": "Notifications" + "notifications": "Notifications", + "transcription": "Transcription" } } diff --git a/src/frontend/src/locales/nl/rooms.json b/src/frontend/src/locales/nl/rooms.json index 99bbaaca..dadc34bb 100644 --- a/src/frontend/src/locales/nl/rooms.json +++ b/src/frontend/src/locales/nl/rooms.json @@ -317,7 +317,7 @@ "receiver": "Het transcript wordt verzonden naar de organisator en medeorganisatoren.", "destination": "Er wordt een nieuw document aangemaakt op", "destinationUnknown": "Een nieuw document wordt aangemaakt", - "language": "Vergadertalen: Frans (fr)", + "language": "Vergadertalen:", "recording": "Start ook een opname" }, "button": { diff --git a/src/frontend/src/locales/nl/settings.json b/src/frontend/src/locales/nl/settings.json index 50c34dc7..340560c1 100644 --- a/src/frontend/src/locales/nl/settings.json +++ b/src/frontend/src/locales/nl/settings.json @@ -68,6 +68,17 @@ }, "permissionsRequired": "Machtigingen vereist" }, + "transcription": { + "heading": "Transcriptie", + "language": { + "label": "Vergadertaal", + "options": { + "french": "Frans (fr)", + "english": "Engels (en)", + "auto": "Automatisch" + } + } + }, "notifications": { "heading": "Geluidsmeldingen", "label": "Geluidsmeldingen voor", @@ -100,6 +111,7 @@ "audio": "Audio", "video": "Video", "general": "Algemeen", - "notifications": "Meldingen" + "notifications": "Meldingen", + "transcription": "Transcriptie" } } diff --git a/src/frontend/src/stores/recording.ts b/src/frontend/src/stores/recording.ts index 8ce95600..661dbe66 100644 --- a/src/frontend/src/stores/recording.ts +++ b/src/frontend/src/stores/recording.ts @@ -1,5 +1,11 @@ import { proxy } from 'valtio' +export enum RecordingLanguage { + ENGLISH = 'en', + FRENCH = 'fr', + AUTOMATIC = 'auto', +} + export enum RecordingStatus { TRANSCRIPT_STARTING, TRANSCRIPT_STARTED, @@ -13,8 +19,10 @@ export enum RecordingStatus { type State = { status: RecordingStatus + language: RecordingLanguage } export const recordingStore = proxy({ status: RecordingStatus.STOPPED, + language: RecordingLanguage.FRENCH, })