feat: add source/target language selectors to edit glossary dialog
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m24s

Users can now change the language pair when editing a glossary:
- EditGlossaryDialog has source/target language dropdowns
- Default target_language changed from 'en' to 'multi' in create dialog
- onSave passes source_language and target_language to the backend
- Backend PATCH endpoint already supports updating these fields

Also fixes:
- CreateGlossaryDialog defaults to 'multi' instead of 'en'
- SUPPORTED_LANGUAGES now includes 'multi' option for target

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-01 00:03:22 +02:00
parent 8fa1ab9ceb
commit 0efdf6a3f4
3 changed files with 42 additions and 6 deletions

View File

@@ -292,7 +292,7 @@ export function CreateGlossaryDialog({
const [name, setName] = useState(''); const [name, setName] = useState('');
const [nameAutoFilled, setNameAutoFilled] = useState(false); const [nameAutoFilled, setNameAutoFilled] = useState(false);
const [sourceLanguage, setSourceLanguage] = useState('fr'); const [sourceLanguage, setSourceLanguage] = useState('fr');
const [targetLanguage, setTargetLanguage] = useState('en'); const [targetLanguage, setTargetLanguage] = useState('multi');
const [terms, setTerms] = useState<GlossaryTermInput[]>([{ source: '', target: '' }]); const [terms, setTerms] = useState<GlossaryTermInput[]>([{ source: '', target: '' }]);
const [fileTerms, setFileTerms] = useState<GlossaryTermInput[]>([]); const [fileTerms, setFileTerms] = useState<GlossaryTermInput[]>([]);
const [selectedTemplate, setSelectedTemplate] = useState<GlossaryTemplate | null>(null); const [selectedTemplate, setSelectedTemplate] = useState<GlossaryTemplate | null>(null);
@@ -305,7 +305,7 @@ export function CreateGlossaryDialog({
setName(''); setName('');
setNameAutoFilled(false); setNameAutoFilled(false);
setSourceLanguage('fr'); setSourceLanguage('fr');
setTargetLanguage('en'); setTargetLanguage('multi');
setTerms([{ source: '', target: '' }]); setTerms([{ source: '', target: '' }]);
setFileTerms([]); setFileTerms([]);
setSelectedTemplate(null); setSelectedTemplate(null);

View File

@@ -17,13 +17,13 @@ import { TermEditor } from './TermEditor';
import { exportGlossaryToCsv, parseCsvToTerms } from './csvUtils'; import { exportGlossaryToCsv, parseCsvToTerms } from './csvUtils';
import { useToast } from '@/components/ui/toast'; import { useToast } from '@/components/ui/toast';
import type { Glossary, GlossaryTermInput } from './types'; import type { Glossary, GlossaryTermInput } from './types';
import { MAX_TERMS_PER_GLOSSARY } from './types'; import { MAX_TERMS_PER_GLOSSARY, SUPPORTED_LANGUAGES } from './types';
interface EditGlossaryDialogProps { interface EditGlossaryDialogProps {
open: boolean; open: boolean;
onOpenChange: (open: boolean) => void; onOpenChange: (open: boolean) => void;
glossary: Glossary | null; glossary: Glossary | null;
onSave: (id: string, data: { name: string; terms: GlossaryTermInput[] }) => Promise<void>; onSave: (id: string, data: { name: string; source_language: string; target_language: string; terms: GlossaryTermInput[] }) => Promise<void>;
isSaving: boolean; isSaving: boolean;
} }
@@ -35,6 +35,8 @@ export function EditGlossaryDialog({
isSaving, isSaving,
}: EditGlossaryDialogProps) { }: EditGlossaryDialogProps) {
const [name, setName] = useState(''); const [name, setName] = useState('');
const [sourceLanguage, setSourceLanguage] = useState('fr');
const [targetLanguage, setTargetLanguage] = useState('multi');
const [terms, setTerms] = useState<GlossaryTermInput[]>([]); const [terms, setTerms] = useState<GlossaryTermInput[]>([]);
const fileInputRef = useRef<HTMLInputElement>(null); const fileInputRef = useRef<HTMLInputElement>(null);
@@ -42,6 +44,8 @@ export function EditGlossaryDialog({
if (glossary && !isInitialized.current) { if (glossary && !isInitialized.current) {
setName(glossary.name); setName(glossary.name);
setSourceLanguage(glossary.source_language || 'fr');
setTargetLanguage(glossary.target_language || 'multi');
setTerms(glossary.terms.map(t => ({ source: t.source, target: t.target }))); setTerms(glossary.terms.map(t => ({ source: t.source, target: t.target })));
isInitialized.current = true; isInitialized.current = true;
} }
@@ -57,9 +61,11 @@ export function EditGlossaryDialog({
await onSave(glossary.id, { await onSave(glossary.id, {
name: name.trim(), name: name.trim(),
source_language: sourceLanguage,
target_language: targetLanguage,
terms: validTerms, terms: validTerms,
}); });
}, [glossary, name, terms, onSave]); }, [glossary, name, sourceLanguage, targetLanguage, terms, onSave]);
const handleExport = useCallback(() => { const handleExport = useCallback(() => {
if (!glossary) return; if (!glossary) return;
@@ -154,6 +160,36 @@ export function EditGlossaryDialog({
/> />
</div> </div>
<div className="flex items-center gap-2">
<div className="flex-1">
<Label className="text-xs text-muted-foreground mb-1 block">Langue source</Label>
<select
value={sourceLanguage}
onChange={e => setSourceLanguage(e.target.value)}
disabled={isSaving}
className="w-full h-9 rounded-md border border-input bg-background px-3 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
>
{SUPPORTED_LANGUAGES.filter(l => l.code !== 'multi').map(l => (
<option key={l.code} value={l.code}>{l.flag} {l.label}</option>
))}
</select>
</div>
<div className="pt-5 text-muted-foreground font-bold"></div>
<div className="flex-1">
<Label className="text-xs text-muted-foreground mb-1 block">Langue cible</Label>
<select
value={targetLanguage}
onChange={e => setTargetLanguage(e.target.value)}
disabled={isSaving}
className="w-full h-9 rounded-md border border-input bg-background px-3 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
>
{SUPPORTED_LANGUAGES.map(l => (
<option key={l.code} value={l.code}>{l.flag} {l.label}</option>
))}
</select>
</div>
</div>
<div className="space-y-2"> <div className="space-y-2">
<Label>Terms ({validTermsCount} valid)</Label> <Label>Terms ({validTermsCount} valid)</Label>
<TermEditor <TermEditor

View File

@@ -185,7 +185,7 @@ export default function GlossariesPage() {
} }
}; };
const handleSaveGlossary = async (id: string, data: { name: string; terms: GlossaryTermInput[] }) => { const handleSaveGlossary = async (id: string, data: { name: string; source_language: string; target_language: string; terms: GlossaryTermInput[] }) => {
try { try {
await updateGlossary(id, data); await updateGlossary(id, data);
setEditDialogOpen(false); setEditDialogOpen(false);