From 5122bfdf99f96b8a9938e8d40c2d424e6c013b1a Mon Sep 17 00:00:00 2001 From: sepehr Date: Sun, 31 May 2026 22:00:40 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20glossary=20selection=20respects=20target?= =?UTF-8?q?=20language=20=E2=80=94=20sort=20by=20source+target,=20reset=20?= =?UTF-8?q?on=20lang=20change,=20fix=20template=20import?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GlossarySelector: filteredGlossaries now sorts matching target_language first so FR→FA appears before FR→EN when translating to Persian - GlossarySelector: toggle auto-select prefers glossary matching targetLang, falls back to first available - useTranslationConfig: reset glossaryId when targetLang changes (was only resetting on sourceLang change) - glossary_routes: set target_language from template data on import (was missing, defaulted to None/en) Co-Authored-By: Claude Opus 4.8 --- .../app/dashboard/translate/GlossarySelector.tsx | 15 ++++++++++++--- .../dashboard/translate/useTranslationConfig.ts | 4 ++-- routes/glossary_routes.py | 1 + 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/dashboard/translate/GlossarySelector.tsx b/frontend/src/app/dashboard/translate/GlossarySelector.tsx index 31c282d..5dba7c5 100644 --- a/frontend/src/app/dashboard/translate/GlossarySelector.tsx +++ b/frontend/src/app/dashboard/translate/GlossarySelector.tsx @@ -239,8 +239,15 @@ export function GlossarySelector({ sourceLang, targetLang, isPro, mode, glossary if (!filterByLang || sourceLang === 'auto') { return glossaries; } - return glossaries.filter(g => g.source_language === sourceLang); - }, [glossaries, filterByLang, sourceLang]); + return glossaries + .filter(g => g.source_language === sourceLang) + .sort((a, b) => { + // Glossaries matching source + target come first + const aMatch = a.target_language === targetLang ? 0 : 1; + const bMatch = b.target_language === targetLang ? 0 : 1; + return aMatch - bMatch; + }); + }, [glossaries, filterByLang, sourceLang, targetLang]); const filteredTemplates = useMemo(() => { if (!filterByLang || sourceLang === 'auto') { @@ -278,7 +285,9 @@ export function GlossarySelector({ sourceLang, targetLang, isPro, mode, glossary if (!nextVal) { onChange(null); } else if (filteredGlossaries.length > 0 && !glossaryId) { - onChange(filteredGlossaries[0].id); + // Prefer glossary matching target language, fall back to first + const matching = filteredGlossaries.find(g => g.target_language === targetLang); + onChange(matching ? matching.id : filteredGlossaries[0].id); } }} className={cn( diff --git a/frontend/src/app/dashboard/translate/useTranslationConfig.ts b/frontend/src/app/dashboard/translate/useTranslationConfig.ts index 9a6cd49..18b856a 100644 --- a/frontend/src/app/dashboard/translate/useTranslationConfig.ts +++ b/frontend/src/app/dashboard/translate/useTranslationConfig.ts @@ -80,10 +80,10 @@ export function useTranslationConfig(hasFile: boolean): UseTranslationConfigRetu } }, [settings.defaultTargetLanguage]); // eslint-disable-line react-hooks/exhaustive-deps - // Reset glossary selection when source language changes + // Reset glossary selection when source or target language changes useEffect(() => { setGlossaryId(null); - }, [sourceLang]); // eslint-disable-line react-hooks/exhaustive-deps + }, [sourceLang, targetLang]); // eslint-disable-line react-hooks/exhaustive-deps // Fetch available (admin-configured) providers useEffect(() => { diff --git a/routes/glossary_routes.py b/routes/glossary_routes.py index 2c96b79..fd3e481 100644 --- a/routes/glossary_routes.py +++ b/routes/glossary_routes.py @@ -597,6 +597,7 @@ async def import_glossary_template( user_id=user.id, name=glossary_name, source_language=template_data.get("source_lang", "fr"), + target_language=template_data.get("target_lang", "en"), created_at=datetime.now(timezone.utc), updated_at=datetime.now(timezone.utc), )