133 lines
4.7 KiB
TypeScript
133 lines
4.7 KiB
TypeScript
/**
|
|
* VoiceLanguageSelect
|
|
*
|
|
* Reusable component for selecting voice/speech recognition language.
|
|
* Defaults to user's profile language.
|
|
* Can be used for speech-to-text, text-to-speech, and translation features.
|
|
*/
|
|
|
|
import React from 'react';
|
|
import { useLanguage } from '../../../providers/language/LanguageContext';
|
|
import styles from './VoiceLanguageSelect.module.css';
|
|
|
|
// Voice language options with full locale codes for Google Cloud Speech
|
|
export interface VoiceLanguageOption {
|
|
code: string; // Full locale code (e.g., 'de-DE')
|
|
label: string; // Display label
|
|
shortCode: string; // Short code for mapping (e.g., 'de')
|
|
flag?: string; // Optional flag emoji
|
|
}
|
|
|
|
// Supported languages for speech recognition
|
|
export const voiceLanguages: VoiceLanguageOption[] = [
|
|
{ code: 'de-DE', label: 'Deutsch', shortCode: 'de', flag: '🇩🇪' },
|
|
{ code: 'de-CH', label: 'Deutsch (Schweiz)', shortCode: 'de', flag: '🇨🇭' },
|
|
{ code: 'en-US', label: 'English (US)', shortCode: 'en', flag: '🇺🇸' },
|
|
{ code: 'en-GB', label: 'English (UK)', shortCode: 'en', flag: '🇬🇧' },
|
|
{ code: 'fr-FR', label: 'Français', shortCode: 'fr', flag: '🇫🇷' },
|
|
{ code: 'fr-CH', label: 'Français (Suisse)', shortCode: 'fr', flag: '🇨🇭' },
|
|
{ code: 'it-IT', label: 'Italiano', shortCode: 'it', flag: '🇮🇹' },
|
|
{ code: 'it-CH', label: 'Italiano (Svizzera)', shortCode: 'it', flag: '🇨🇭' },
|
|
{ code: 'es-ES', label: 'Español', shortCode: 'es', flag: '🇪🇸' },
|
|
{ code: 'pt-BR', label: 'Português', shortCode: 'pt', flag: '🇧🇷' },
|
|
];
|
|
|
|
// Map user profile language (short code) to default voice language (full code)
|
|
const profileToVoiceLanguage: Record<string, string> = {
|
|
'de': 'de-DE',
|
|
'en': 'en-US',
|
|
'fr': 'fr-FR',
|
|
'it': 'it-IT',
|
|
'es': 'es-ES',
|
|
'pt': 'pt-BR',
|
|
};
|
|
|
|
export interface VoiceLanguageSelectProps {
|
|
value: string;
|
|
onChange: (languageCode: string) => void;
|
|
disabled?: boolean;
|
|
compact?: boolean; // Compact mode shows only flag/short code
|
|
showFlags?: boolean; // Show flag emojis
|
|
className?: string;
|
|
title?: string;
|
|
}
|
|
|
|
/**
|
|
* Get the default voice language based on user's profile language
|
|
*/
|
|
export const getDefaultVoiceLanguage = (profileLanguage?: string): string => {
|
|
if (profileLanguage && profileToVoiceLanguage[profileLanguage]) {
|
|
return profileToVoiceLanguage[profileLanguage];
|
|
}
|
|
return 'de-DE'; // Default fallback
|
|
};
|
|
|
|
export const VoiceLanguageSelect: React.FC<VoiceLanguageSelectProps> = ({
|
|
value,
|
|
onChange,
|
|
disabled = false,
|
|
compact = false,
|
|
showFlags = true,
|
|
className = '',
|
|
title = 'Sprache für Spracherkennung',
|
|
}) => {
|
|
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
onChange(e.target.value);
|
|
};
|
|
|
|
return (
|
|
<div className={`${styles.container} ${compact ? styles.compact : ''} ${className}`}>
|
|
<select
|
|
className={styles.select}
|
|
value={value}
|
|
onChange={handleChange}
|
|
disabled={disabled}
|
|
title={title}
|
|
>
|
|
{voiceLanguages.map((lang) => (
|
|
<option key={lang.code} value={lang.code}>
|
|
{showFlags && lang.flag ? `${lang.flag} ` : ''}
|
|
{compact ? lang.code.split('-')[0].toUpperCase() : lang.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Hook to manage voice language state with user profile default
|
|
*/
|
|
export const useVoiceLanguage = (initialValue?: string) => {
|
|
const { currentLanguage } = useLanguage();
|
|
|
|
// Track if user has manually changed the language
|
|
const hasManuallyChanged = React.useRef(false);
|
|
|
|
// Initialize with user's profile language (or provided initial value)
|
|
const [voiceLanguage, setVoiceLanguage] = React.useState<string>(
|
|
initialValue || getDefaultVoiceLanguage(currentLanguage)
|
|
);
|
|
|
|
// Update voice language when user profile language changes (only if not manually set)
|
|
React.useEffect(() => {
|
|
if (!initialValue && !hasManuallyChanged.current) {
|
|
const newDefault = getDefaultVoiceLanguage(currentLanguage);
|
|
setVoiceLanguage(newDefault);
|
|
}
|
|
}, [currentLanguage, initialValue]);
|
|
|
|
// Wrapper to track manual changes
|
|
const handleSetVoiceLanguage = React.useCallback((newLanguage: string) => {
|
|
hasManuallyChanged.current = true;
|
|
setVoiceLanguage(newLanguage);
|
|
}, []);
|
|
|
|
return {
|
|
voiceLanguage,
|
|
setVoiceLanguage: handleSetVoiceLanguage,
|
|
voiceLanguages,
|
|
};
|
|
};
|
|
|
|
export default VoiceLanguageSelect;
|