// eveai_chat_client/static/assets/js/composables/useTranslation.js import { ref, computed, onMounted } from 'vue'; /** * Vue 3 Composable for translation management * Provides direct backend API communication for translations */ export function useTranslation() { const isTranslationReady = ref(false); const currentLanguage = ref('en'); const isTranslating = ref(false); const lastError = ref(null); // Check if translation system is available const checkTranslationReady = () => { // Translation is altijd ready omdat we de backend API gebruiken // Controleer alleen of we in een browser environment zijn if (typeof window !== 'undefined' && typeof fetch !== 'undefined') { isTranslationReady.value = true; return true; } return false; }; onMounted(() => { // Eenvoudige check - geen retry mechanism nodig checkTranslationReady(); }); /** * Translate text to target language * @param {string} text - Text to translate * @param {string} targetLang - Target language code * @param {string|null} sourceLang - Source language code (optional) * @param {string|null} context - Translation context (optional) * @param {string} apiPrefix - API prefix for tenant routing * @returns {Promise} Translation result */ const translate = async (text, targetLang, sourceLang = null, context = null, apiPrefix = '') => { if (!text || !text.trim()) { const error = new Error('No text provided for translation'); lastError.value = error; throw error; } isTranslating.value = true; lastError.value = null; try { // Bepaal de juiste API URL const baseUrl = apiPrefix || window.chatConfig?.apiPrefix || ''; const apiUrl = `${baseUrl}/api/translate`; // Maak de request payload const payload = { text: text, target_lang: targetLang }; // Voeg optionele parameters toe if (sourceLang) payload.source_lang = sourceLang; if (context) payload.context = context; // Maak de HTTP request const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }, credentials: 'same-origin', // Voor sessie cookies body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); // Update current language if translation was successful if (result.success) { currentLanguage.value = targetLang; } return result; } catch (error) { console.error('Translation error in composable:', error); lastError.value = error; throw error; } finally { isTranslating.value = false; } }; /** * Translate text with automatic error handling and loading state * @param {string} text - Text to translate * @param {string} targetLang - Target language code * @param {Object} options - Translation options * @returns {Promise} Translated text or null on error */ const translateSafe = async (text, targetLang, options = {}) => { const { sourceLang = null, context = null, apiPrefix = '', fallbackText = text } = options; try { const result = await translate(text, targetLang, sourceLang, context, apiPrefix); return result.success ? result.translated_text : fallbackText; } catch (error) { console.warn('Safe translation failed, using fallback:', error.message); return fallbackText; } }; /** * Batch translate multiple texts * @param {Array} texts - Array of texts to translate * @param {string} targetLang - Target language code * @param {Object} options - Translation options * @returns {Promise>} Array of translated texts */ const translateBatch = async (texts, targetLang, options = {}) => { const results = await Promise.allSettled( texts.map(text => translateSafe(text, targetLang, options)) ); return results.map((result, index) => result.status === 'fulfilled' ? result.value : texts[index] ); }; /** * Get current language from chatConfig or fallback */ const getCurrentLanguage = () => { return window.chatConfig?.language || currentLanguage.value || 'en'; }; /** * Get API prefix from chatConfig or fallback */ const getApiPrefix = () => { return window.chatConfig?.apiPrefix || ''; }; return { // State isTranslationReady, currentLanguage: computed(() => getCurrentLanguage()), isTranslating, lastError, // Methods translate, translateSafe, translateBatch, // Utilities getCurrentLanguage, getApiPrefix }; } // Global cache for constants - shared across all component instances const CONSTANTS_CACHE = { currentLanguage: null, translations: {} }; /** * Composable for translating application constants with global caching * This ensures all component instances share the same cached translations */ export function useConstantsTranslation() { const { translateSafe } = useTranslation(); /** * Translate constants with global caching * @param {Object} constants - Object with key-value pairs of constants to translate * @param {string} targetLang - Target language code * @param {Object} options - Translation options * @returns {Promise} Object with translated constants */ const translateConstants = async (constants, targetLang, options = {}) => { console.log('useConstantsTranslation: translateConstants called', { targetLang, currentCached: CONSTANTS_CACHE.currentLanguage }); // Check if we already have translations for this language if (CONSTANTS_CACHE.currentLanguage === targetLang && CONSTANTS_CACHE.translations) { console.log('useConstantsTranslation: Using cached translations for', targetLang); return { ...CONSTANTS_CACHE.translations }; } console.log('useConstantsTranslation: Translating constants to', targetLang); try { const translated = {}; // Translate each constant for (const [key, originalText] of Object.entries(constants)) { translated[key] = await translateSafe(originalText, targetLang, { context: 'constants', fallbackText: originalText, ...options }); } // Update global cache CONSTANTS_CACHE.currentLanguage = targetLang; CONSTANTS_CACHE.translations = translated; console.log('useConstantsTranslation: Successfully translated and cached constants'); console.log('useConstantsTranslation: Current language:', CONSTANTS_CACHE.currentLanguage); console.log('useConstantsTranslation: Cached translations:', CONSTANTS_CACHE.translations); return translated; } catch (error) { console.error('useConstantsTranslation: Error translating constants:', error); // Return original constants as fallback return { ...constants }; } }; /** * Get cached translations for current language * @returns {Object|null} Cached translations or null if not available */ const getCachedTranslations = () => { return CONSTANTS_CACHE.currentLanguage ? { ...CONSTANTS_CACHE.translations } : null; }; /** * Clear the constants cache (useful for testing or language reset) */ const clearCache = () => { CONSTANTS_CACHE.currentLanguage = null; CONSTANTS_CACHE.translations = {}; console.log('useConstantsTranslation: Cache cleared'); }; /** * Get current cached language */ const getCachedLanguage = () => { return CONSTANTS_CACHE.currentLanguage; }; return { translateConstants, getCachedTranslations, clearCache, getCachedLanguage }; } /** * Simplified composable for basic translation needs * Use this when you only need simple text translation */ export function useTranslationClient() { const { translate, translateSafe, isTranslationReady, isTranslating, lastError } = useTranslation(); return { translate, translateSafe, isTranslationReady, isTranslating, lastError }; } /** * Composable for reactive text translation * Automatically translates text when language changes */ export function useReactiveTranslation(text, options = {}) { const { translateSafe, currentLanguage } = useTranslation(); const translatedText = ref(text); const isLoading = ref(false); const { context = null, sourceLang = null, autoTranslate = true } = options; // Watch for language changes and auto-translate if (autoTranslate) { // We'll implement this when we have proper reactivity setup // For now, provide manual translation method } const updateTranslation = async (newLanguage = null) => { const targetLang = newLanguage || currentLanguage.value; if (!text || targetLang === sourceLang) { translatedText.value = text; return; } isLoading.value = true; try { const result = await translateSafe(text, targetLang, { sourceLang, context, apiPrefix: window.chatConfig?.apiPrefix || '' }); translatedText.value = result; } finally { isLoading.value = false; } }; return { translatedText, isLoading, updateTranslation }; }