From 31f5683b7cc3d82e43ad1c3f99d59d28b8059375 Mon Sep 17 00:00:00 2001 From: digpalsinghpanwar Date: Fri, 26 Jun 2026 14:27:05 +0530 Subject: [PATCH] Auto Detect language --- src/components/LanguageProvider.tsx | 11 ++++---- .../components/language-selection-dialog.tsx | 28 +++++++++---------- src/hooks/store/chat/index.ts | 18 ++++++++++-- src/layouts/chat-layout/index.tsx | 4 +-- 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/components/LanguageProvider.tsx b/src/components/LanguageProvider.tsx index 9425a4d..6d35e55 100644 --- a/src/components/LanguageProvider.tsx +++ b/src/components/LanguageProvider.tsx @@ -9,9 +9,7 @@ import gu from '../../translations/gu.json'; import kn from '../../translations/kn.json'; import ml from '../../translations/ml.json'; import as_ from '../../translations/as.json'; -import { DEFAULT_LANGUAGE } from './screens-component/chat-screen/config'; - -type LanguageCode = 'hi' | 'en' | 'bn' | 'te' | 'mr' | 'ta' | 'gu' | 'kn' | 'ml' | 'as'; +import { DEFAULT_LANGUAGE, LANGUAGES, type LanguageCode } from './screens-component/chat-screen/config'; interface LanguageContextType { language: LanguageCode; @@ -30,12 +28,13 @@ const LanguageContext = createContext(undefined export const LanguageProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [language, setLanguageState] = useState(() => { const saved = localStorage.getItem('app_language'); - return (saved as LanguageCode) || DEFAULT_LANGUAGE; + return saved && saved in LANGUAGES ? (saved as LanguageCode) : DEFAULT_LANGUAGE; }); const setLanguage = (lang: LanguageCode) => { - setLanguageState(lang); - localStorage.setItem('app_language', lang); + const nextLanguage = lang in LANGUAGES ? lang : DEFAULT_LANGUAGE; + setLanguageState(nextLanguage); + localStorage.setItem('app_language', nextLanguage); }; const t = useCallback((key: string, params?: Record): string | string[] => { diff --git a/src/components/screens-component/chat-screen/components/language-selection-dialog.tsx b/src/components/screens-component/chat-screen/components/language-selection-dialog.tsx index 9338900..b70df8a 100644 --- a/src/components/screens-component/chat-screen/components/language-selection-dialog.tsx +++ b/src/components/screens-component/chat-screen/components/language-selection-dialog.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import React from "react"; import { cn } from "@/lib/utils"; import { Popover, @@ -7,7 +7,6 @@ import { } from "@/components/ui/popover"; import { LANGUAGES } from "../config"; import { useLanguage } from "@/components/LanguageProvider"; -import { useChatStore } from "@/hooks/store/chat"; type LanguageSelectionDropdownProps = { children: React.ReactNode; @@ -16,20 +15,19 @@ type LanguageSelectionDropdownProps = { export function LanguageSelectionDropdown({ children }: LanguageSelectionDropdownProps) { - const { language: selectedLanguage, setLanguage } = useLanguage(); - const fetchNotifications = useChatStore((state) => state.fetchNotifications); - const [open, setOpen] = useState(false); + const { language: selectedLanguage } = useLanguage(); - const handleLanguageSelect = (code: keyof typeof LANGUAGES) => { - setLanguage(code); - setOpen(false); - void fetchNotifications(); - }; + const disabledTrigger = React.isValidElement(children) + ? React.cloneElement(children as React.ReactElement, { + disabled: true, + "aria-disabled": true + }) + : children; return ( - + - {children} + {disabledTrigger} handleLanguageSelect(language.code)} + disabled className={cn( - "w-full flex items-center px-5 py-3.5 transition-colors text-left cursor-pointer", + "w-full flex items-center px-5 py-3.5 transition-colors text-left cursor-not-allowed", isActive ? "bg-[#FEF2B2] dark:bg-[#EFC300] text-gray-900 font-bold" - : "bg-white dark:bg-[#5D5D5D] text-gray-800 dark:text-white font-medium hover:bg-gray-50 dark:hover:brightness-110" + : "bg-white dark:bg-[#5D5D5D] text-gray-800 dark:text-white font-medium opacity-70" )} > diff --git a/src/hooks/store/chat/index.ts b/src/hooks/store/chat/index.ts index 5aba65b..342cd28 100644 --- a/src/hooks/store/chat/index.ts +++ b/src/hooks/store/chat/index.ts @@ -3,7 +3,7 @@ import type { ChatMessage, TextMessage } from "@/components/screens-component/chat-screen/components/bubbles/chat-types"; -import { LANGUAGES, type LanguageCode } from "@/components/screens-component/chat-screen/config"; +import { DEFAULT_LANGUAGE, LANGUAGES, type LanguageCode } from "@/components/screens-component/chat-screen/config"; import { fetchSuggestions, @@ -99,7 +99,12 @@ type ChatStore = { sessionId: string | null; initializeSession: (user: any) => Promise; sendText: (text: string, language: string, t?: any) => Promise; - sendAudio: (blob: Blob, sessionId: string, language: string) => Promise; + sendAudio: ( + blob: Blob, + sessionId: string, + language: string, + onLanguageDetected?: (language: LanguageCode) => void + ) => Promise; sendImage: (imageFile: File, language: string, t?: any) => Promise; sendQuickAction: (id: string, language: string, t?: any) => void; sendQuickReply: (payload: string, language: string, t?: any) => void; @@ -285,6 +290,11 @@ function getResponseLanguage(language: string): LanguageCode | undefined { return language in LANGUAGES ? (language as LanguageCode) : undefined; } +function getTranscriptionLanguage(status?: string, langCode?: string): LanguageCode { + if (status !== "success" || !langCode) return DEFAULT_LANGUAGE; + return getResponseLanguage(langCode) ?? DEFAULT_LANGUAGE; +} + function makeImageMessage(imageUrl: string, caption?: string): ChatMessage { return { id: crypto.randomUUID(), @@ -839,7 +849,7 @@ export const useChatStore = create((set, get) => ({ } }, - sendAudio: async (blob, sessionId, language) => { + sendAudio: async (blob, sessionId, language, onLanguageDetected) => { if (!blob) return; set({ isTranscribing: true }); @@ -912,6 +922,7 @@ export const useChatStore = create((set, get) => ({ sessionId, language ); + onLanguageDetected?.(getTranscriptionLanguage(transcription?.status, transcription?.lang_code)); if (transcription && transcription.text) { set((state) => ({ @@ -924,6 +935,7 @@ export const useChatStore = create((set, get) => ({ } } catch (error) { console.error("Transcription error:", error); + onLanguageDetected?.(DEFAULT_LANGUAGE); set({ isAssistantTyping: false, isTranscribing: false }); set({ toast: { message: "Transcription failed. Please try again.", type: "error" } }); throw error; diff --git a/src/layouts/chat-layout/index.tsx b/src/layouts/chat-layout/index.tsx index 7044f10..91062a1 100644 --- a/src/layouts/chat-layout/index.tsx +++ b/src/layouts/chat-layout/index.tsx @@ -46,7 +46,7 @@ function ChatLayout() { const setToast = useChatStore((s) => s.setToast); const fetchLocation = useChatStore((s) => s.fetchLocation); - const { language, t } = useLanguage(); + const { language, setLanguage, t } = useLanguage(); const [settingsOpen, setSettingsOpen] = useState(false); const [showLocationPrompt, setShowLocationPrompt] = useState(false); @@ -131,7 +131,7 @@ function ChatLayout() { sendText(text, language, t); } else if (voice) { try { - await sendAudio(voice, sessionId || '', language); + await sendAudio(voice, sessionId || '', language, setLanguage); } catch (error) { console.error(error); }