- verbeteringen client
- Enkel nog probleem met vertaling van de ProgressTracker constanten
This commit is contained in:
@@ -8,7 +8,7 @@ import { ref, computed, onMounted } from 'vue';
|
||||
*/
|
||||
export function useTranslation() {
|
||||
const isTranslationReady = ref(false);
|
||||
const currentLanguage = ref('nl');
|
||||
const currentLanguage = ref('en');
|
||||
const isTranslating = ref(false);
|
||||
const lastError = ref(null);
|
||||
|
||||
@@ -139,7 +139,7 @@ export function useTranslation() {
|
||||
* Get current language from chatConfig or fallback
|
||||
*/
|
||||
const getCurrentLanguage = () => {
|
||||
return window.chatConfig?.language || currentLanguage.value || 'nl';
|
||||
return window.chatConfig?.language || currentLanguage.value || 'en';
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -215,6 +215,8 @@ export function useConstantsTranslation() {
|
||||
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);
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
// eveai_chat_client/static/assets/js/composables/useTranslation.js
|
||||
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
|
||||
/**
|
||||
* Vue 3 Composable for translation management
|
||||
* Provides modern alternative to window.TranslationClient
|
||||
*/
|
||||
export function useTranslation() {
|
||||
const isTranslationReady = ref(false);
|
||||
const currentLanguage = ref('nl');
|
||||
const isTranslating = ref(false);
|
||||
const lastError = ref(null);
|
||||
|
||||
// Check if translation system is available with retry mechanism
|
||||
const checkTranslationReady = () => {
|
||||
if (window.TranslationClient && typeof window.TranslationClient.translate === 'function') {
|
||||
isTranslationReady.value = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// Initial check
|
||||
if (checkTranslationReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Retry mechanism - wait for TranslationClient to become available
|
||||
let retryCount = 0;
|
||||
const maxRetries = 10;
|
||||
const retryInterval = 100; // 100ms
|
||||
|
||||
const retryCheck = () => {
|
||||
if (checkTranslationReady()) {
|
||||
return; // Success!
|
||||
}
|
||||
|
||||
retryCount++;
|
||||
if (retryCount < maxRetries) {
|
||||
setTimeout(retryCheck, retryInterval);
|
||||
} else {
|
||||
console.warn('TranslationClient is not available after retries');
|
||||
isTranslationReady.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Start retry process
|
||||
setTimeout(retryCheck, retryInterval);
|
||||
});
|
||||
|
||||
/**
|
||||
* 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<object>} Translation result
|
||||
*/
|
||||
const translate = async (text, targetLang, sourceLang = null, context = null, apiPrefix = '') => {
|
||||
if (!isTranslationReady.value || !window.TranslationClient) {
|
||||
const error = new Error('Translation system not ready');
|
||||
lastError.value = error;
|
||||
throw error;
|
||||
}
|
||||
|
||||
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 {
|
||||
const result = await window.TranslationClient.translate(
|
||||
text,
|
||||
targetLang,
|
||||
sourceLang,
|
||||
context,
|
||||
apiPrefix
|
||||
);
|
||||
|
||||
// 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<string|null>} 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<string>} texts - Array of texts to translate
|
||||
* @param {string} targetLang - Target language code
|
||||
* @param {Object} options - Translation options
|
||||
* @returns {Promise<Array<string>>} 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
}
|
||||
181
eveai_chat_client/static/assets/js/services/LanguageProvider.js
Normal file
181
eveai_chat_client/static/assets/js/services/LanguageProvider.js
Normal file
@@ -0,0 +1,181 @@
|
||||
// LanguageProvider.js - Central language management system
|
||||
import { ref, reactive, computed, provide, inject } from 'vue';
|
||||
import { useConstantsTranslation } from '../composables/useTranslation.js';
|
||||
|
||||
// Injection key for type safety
|
||||
export const LANGUAGE_PROVIDER_KEY = Symbol('LanguageProvider');
|
||||
|
||||
/**
|
||||
* Language Provider Service
|
||||
* Central management of language state and translations
|
||||
*/
|
||||
export function createLanguageProvider(initialLanguage = 'en', apiPrefix = '') {
|
||||
// Reactive state
|
||||
const currentLanguage = ref(initialLanguage);
|
||||
const isTranslating = ref(false);
|
||||
const translationError = ref(null);
|
||||
|
||||
// Translation composable
|
||||
const { translateConstants, getCachedTranslations, clearCache } = useConstantsTranslation();
|
||||
|
||||
// Component-specific translations cache
|
||||
const componentTranslations = reactive({});
|
||||
|
||||
/**
|
||||
* Register a component for translations with component-specific caching
|
||||
*/
|
||||
const registerComponent = (componentName, originalTexts) => {
|
||||
console.log(`LanguageProvider: Registering component ${componentName} with language ${currentLanguage.value}`);
|
||||
|
||||
if (!componentTranslations[componentName]) {
|
||||
componentTranslations[componentName] = reactive({
|
||||
original: originalTexts,
|
||||
translated: { ...originalTexts }, // Start with original English texts
|
||||
isLoading: false,
|
||||
error: null
|
||||
});
|
||||
|
||||
// Force initial translation if current language is not English
|
||||
if (currentLanguage.value !== 'en') {
|
||||
console.log(`LanguageProvider: Component ${componentName} needs initial translation to ${currentLanguage.value}`);
|
||||
translateComponentTexts(componentName, currentLanguage.value);
|
||||
}
|
||||
}
|
||||
|
||||
return componentTranslations[componentName];
|
||||
};
|
||||
|
||||
/**
|
||||
* Translate texts for a specific component
|
||||
*/
|
||||
const translateComponentTexts = async (componentName, targetLanguage) => {
|
||||
const component = componentTranslations[componentName];
|
||||
if (!component) {
|
||||
console.warn(`LanguageProvider: Component ${componentName} not found for translation`);
|
||||
return;
|
||||
}
|
||||
|
||||
component.isLoading = true;
|
||||
component.error = null;
|
||||
|
||||
try {
|
||||
if (targetLanguage === 'en') {
|
||||
// For English, use original texts (no translation needed)
|
||||
component.translated = { ...component.original };
|
||||
console.log(`LanguageProvider: Using original English texts for ${componentName}`);
|
||||
} else {
|
||||
// For other languages, translate from English
|
||||
console.log(`LanguageProvider: Translating ${componentName} from English to ${targetLanguage}`);
|
||||
const translatedTexts = await translateConstants(
|
||||
component.original,
|
||||
targetLanguage,
|
||||
{
|
||||
context: componentName,
|
||||
apiPrefix
|
||||
}
|
||||
);
|
||||
component.translated = translatedTexts;
|
||||
console.log(`LanguageProvider: Successfully translated ${componentName} to ${targetLanguage}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`LanguageProvider: Translation error for ${componentName}:`, error);
|
||||
component.error = error;
|
||||
// Fallback to original English texts
|
||||
component.translated = { ...component.original };
|
||||
} finally {
|
||||
component.isLoading = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update language for all registered components
|
||||
*/
|
||||
const setLanguage = async (newLanguage) => {
|
||||
if (currentLanguage.value === newLanguage) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('LanguageProvider: Setting language to', newLanguage);
|
||||
currentLanguage.value = newLanguage;
|
||||
isTranslating.value = true;
|
||||
translationError.value = null;
|
||||
|
||||
try {
|
||||
// Update all registered components
|
||||
const translationPromises = Object.keys(componentTranslations).map(componentName =>
|
||||
translateComponentTexts(componentName, newLanguage)
|
||||
);
|
||||
|
||||
await Promise.all(translationPromises);
|
||||
console.log(`LanguageProvider: Successfully updated all components to ${newLanguage}`);
|
||||
} catch (error) {
|
||||
console.error('LanguageProvider: Error setting language:', error);
|
||||
translationError.value = error;
|
||||
} finally {
|
||||
isTranslating.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get translations voor een specifieke component
|
||||
*/
|
||||
const getComponentTranslations = (componentName) => {
|
||||
return componentTranslations[componentName] || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear alle caches
|
||||
*/
|
||||
const clearAllCaches = () => {
|
||||
clearCache();
|
||||
Object.keys(componentTranslations).forEach(key => {
|
||||
delete componentTranslations[key];
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
// State
|
||||
currentLanguage: computed(() => currentLanguage.value),
|
||||
isTranslating: computed(() => isTranslating.value),
|
||||
translationError: computed(() => translationError.value),
|
||||
|
||||
// Methods
|
||||
registerComponent,
|
||||
setLanguage,
|
||||
getComponentTranslations,
|
||||
clearAllCaches,
|
||||
|
||||
// Computed
|
||||
componentTranslations: computed(() => componentTranslations)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Composable voor het gebruiken van de Language Provider
|
||||
*/
|
||||
export function useLanguageProvider() {
|
||||
const provider = inject(LANGUAGE_PROVIDER_KEY);
|
||||
|
||||
if (!provider) {
|
||||
throw new Error('useLanguageProvider must be used within a LanguageProvider');
|
||||
}
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Composable voor component-specifieke vertalingen
|
||||
*/
|
||||
export function useComponentTranslations(componentName, originalTexts) {
|
||||
const provider = useLanguageProvider();
|
||||
|
||||
// Registreer component bij eerste gebruik
|
||||
const translations = provider.registerComponent(componentName, originalTexts);
|
||||
|
||||
return {
|
||||
translations: computed(() => translations.translated),
|
||||
isLoading: computed(() => translations.isLoading),
|
||||
error: computed(() => translations.error),
|
||||
currentLanguage: provider.currentLanguage
|
||||
};
|
||||
}
|
||||
@@ -43,6 +43,10 @@ import ProgressTracker from './ProgressTracker.vue';
|
||||
import LanguageSelector from './LanguageSelector.vue';
|
||||
import ChatInput from './ChatInput.vue';
|
||||
|
||||
// Import language provider
|
||||
import { createLanguageProvider, LANGUAGE_PROVIDER_KEY } from '../js/services/LanguageProvider.js';
|
||||
import { provide } from 'vue';
|
||||
|
||||
export default {
|
||||
name: 'ChatApp',
|
||||
components: {
|
||||
@@ -54,12 +58,28 @@ export default {
|
||||
ProgressTracker,
|
||||
ChatInput
|
||||
},
|
||||
|
||||
setup() {
|
||||
// Haal initiële taal uit chatConfig
|
||||
const initialLanguage = window.chatConfig?.language || 'nl';
|
||||
const apiPrefix = window.chatConfig?.apiPrefix || '';
|
||||
|
||||
// Creëer language provider
|
||||
const languageProvider = createLanguageProvider(initialLanguage, apiPrefix);
|
||||
|
||||
// Provide aan alle child components
|
||||
provide(LANGUAGE_PROVIDER_KEY, languageProvider);
|
||||
|
||||
return {
|
||||
languageProvider
|
||||
};
|
||||
},
|
||||
|
||||
data() {
|
||||
// Maak een lokale kopie van de chatConfig om undefined errors te voorkomen
|
||||
const chatConfig = window.chatConfig || {};
|
||||
const settings = chatConfig.settings || {};
|
||||
const initialLanguage = chatConfig.language || 'nl';
|
||||
const initialLanguage = chatConfig.language || 'en';
|
||||
const originalExplanation = chatConfig.explanation || '';
|
||||
const tenantMake = chatConfig.tenantMake || {};
|
||||
|
||||
@@ -331,7 +351,7 @@ export default {
|
||||
// Add a placeholder AI message that will be updated by the progress tracker
|
||||
const placeholderMessage = {
|
||||
id: this.messageIdCounter++,
|
||||
content: 'Bezig met verwerken...',
|
||||
// content: 'Bezig met verwerken...',
|
||||
sender: 'ai',
|
||||
type: 'text',
|
||||
timestamp: new Date().toISOString(),
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
{{ message.content }}
|
||||
</div>
|
||||
<button v-if="message.retryable" @click="$emit('retry-message', message.id)" class="retry-btn">
|
||||
Opnieuw proberen
|
||||
{{ messageTexts.retry }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -116,6 +116,7 @@
|
||||
import DynamicForm from './DynamicForm.vue';
|
||||
import ProgressTracker from './ProgressTracker.vue';
|
||||
import { useIconManager } from '../js/composables/useIconManager.js';
|
||||
import { useComponentTranslations } from '../js/services/LanguageProvider.js';
|
||||
|
||||
export default {
|
||||
name: 'ChatMessage',
|
||||
@@ -129,7 +130,25 @@ export default {
|
||||
// Watch message.formData.icon for automatic icon loading
|
||||
watchIcon(() => props.message.formData?.icon);
|
||||
|
||||
return {};
|
||||
// Use component translations from provider (English as base language)
|
||||
const originalTexts = {
|
||||
retry: 'Try again',
|
||||
copy: 'Copy',
|
||||
timestamp: 'Timestamp',
|
||||
errorMessage: 'An error occurred while processing your request.'
|
||||
};
|
||||
|
||||
const { translations, isLoading, error, currentLanguage } = useComponentTranslations(
|
||||
'chat_message',
|
||||
originalTexts
|
||||
);
|
||||
|
||||
return {
|
||||
messageTexts: translations,
|
||||
translationLoading: isLoading,
|
||||
translationError: error,
|
||||
currentLanguage
|
||||
};
|
||||
},
|
||||
props: {
|
||||
message: {
|
||||
@@ -163,12 +182,10 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// Luister naar taalwijzigingen
|
||||
document.addEventListener('language-changed', this.handleLanguageChange);
|
||||
// Component initialization if needed
|
||||
},
|
||||
beforeUnmount() {
|
||||
// Verwijder event listener bij verwijderen component
|
||||
document.removeEventListener('language-changed', this.handleLanguageChange);
|
||||
// Component cleanup if needed
|
||||
},
|
||||
computed: {
|
||||
hasFormData() {
|
||||
@@ -214,22 +231,17 @@ export default {
|
||||
return hasActualValues;
|
||||
},
|
||||
|
||||
async handleLanguageChange(event) {
|
||||
// Controleer of dit het eerste bericht is in een gesprek met maar één bericht
|
||||
// Dit wordt al afgehandeld door MessageHistory component, dus we hoeven hier niets te doen
|
||||
// De implementatie hiervan blijft in MessageHistory om dubbele vertaling te voorkomen
|
||||
},
|
||||
|
||||
handleSpecialistError(eventData) {
|
||||
console.log('ChatMessage received specialist-error event:', eventData);
|
||||
|
||||
// Creëer een error message met correcte styling
|
||||
// Create an error message with correct styling
|
||||
this.message.type = 'error';
|
||||
this.message.content = eventData.message || 'Er is een fout opgetreden bij het verwerken van uw verzoek.';
|
||||
this.message.content = eventData.message || this.messageTexts.errorMessage;
|
||||
this.message.retryable = true;
|
||||
this.message.error = true; // Voeg error flag toe voor styling
|
||||
this.message.error = true; // Add error flag for styling
|
||||
|
||||
// Bubble up naar parent component voor verdere afhandeling
|
||||
// Bubble up to parent component for further handling
|
||||
this.$emit('specialist-error', {
|
||||
messageId: this.message.id,
|
||||
...eventData
|
||||
|
||||
@@ -21,12 +21,26 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useLanguageProvider } from '../js/services/LanguageProvider.js';
|
||||
|
||||
export default {
|
||||
name: 'LanguageSelector',
|
||||
setup() {
|
||||
// Optionally use provider for reactive current language
|
||||
try {
|
||||
const provider = useLanguageProvider();
|
||||
return {
|
||||
providerLanguage: provider.currentLanguage
|
||||
};
|
||||
} catch {
|
||||
// Provider not available, use props
|
||||
return {};
|
||||
}
|
||||
},
|
||||
props: {
|
||||
initialLanguage: {
|
||||
type: String,
|
||||
default: 'nl'
|
||||
default: 'en'
|
||||
},
|
||||
currentLanguage: {
|
||||
type: String,
|
||||
@@ -53,11 +67,17 @@ export default {
|
||||
this.$emit('language-changed', this.selectedLanguage);
|
||||
|
||||
// DOM event
|
||||
const event = new CustomEvent('vue:language-changed', {
|
||||
const event = new CustomEvent('language-changed', {
|
||||
detail: { language: this.selectedLanguage }
|
||||
});
|
||||
document.dispatchEvent(event);
|
||||
},
|
||||
computed: {
|
||||
// Use provider language if available, otherwise use props
|
||||
effectiveCurrentLanguage() {
|
||||
return this.providerLanguage || this.currentLanguage || this.initialLanguage;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getAvailableLanguages() {
|
||||
const languages = [];
|
||||
@@ -109,7 +129,7 @@ export default {
|
||||
this.$emit('language-changed', languageCode);
|
||||
|
||||
// DOM event
|
||||
const event = new CustomEvent('vue:language-changed', {
|
||||
const event = new CustomEvent('language-changed', {
|
||||
detail: { language: languageCode }
|
||||
});
|
||||
document.dispatchEvent(event);
|
||||
|
||||
@@ -53,10 +53,34 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useTranslationClient, useConstantsTranslation } from '../js/composables/useTranslation.js';
|
||||
import { useComponentTranslations } from '../js/services/LanguageProvider.js';
|
||||
|
||||
export default {
|
||||
name: 'ProgressTracker',
|
||||
setup() {
|
||||
// Define original English texts (base language for developers)
|
||||
const originalTexts = {
|
||||
error: 'Error while processing',
|
||||
completed: 'Processing completed',
|
||||
processing: 'Processing...'
|
||||
};
|
||||
|
||||
// Gebruik component translations
|
||||
const { translations, isLoading, error, currentLanguage } = useComponentTranslations(
|
||||
'progress_tracker',
|
||||
originalTexts
|
||||
);
|
||||
|
||||
console.log('Translations:', translations);
|
||||
console.log('Current language:', currentLanguage);
|
||||
|
||||
return {
|
||||
statusTexts: translations,
|
||||
translationLoading: isLoading,
|
||||
translationError: error,
|
||||
currentLanguage
|
||||
};
|
||||
},
|
||||
props: {
|
||||
taskId: {
|
||||
type: String,
|
||||
@@ -76,99 +100,56 @@ export default {
|
||||
connecting: true,
|
||||
error: null,
|
||||
progressLines: [],
|
||||
eventSource: null,
|
||||
// Vertaalde status teksten
|
||||
translatedStatusTexts: {
|
||||
error: 'Error while processing',
|
||||
completed: 'Processing completed',
|
||||
processing: 'Processing...'
|
||||
},
|
||||
currentLanguage: 'nl'
|
||||
eventSource: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isProcessing() {
|
||||
return !this.isCompleted && !this.hasError && !this.connecting;
|
||||
},
|
||||
// Computed properties voor vertaalde status teksten
|
||||
// Computed properties voor vertaalde status teksten uit provider
|
||||
errorText() {
|
||||
return this.translatedStatusTexts.error;
|
||||
return this.statusTexts.error;
|
||||
},
|
||||
completedText() {
|
||||
return this.translatedStatusTexts.completed;
|
||||
return this.statusTexts.completed;
|
||||
},
|
||||
processingText() {
|
||||
return this.translatedStatusTexts.processing;
|
||||
return this.statusTexts.processing;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// Create named handler for language changes
|
||||
this.languageChangeHandler = (event) => {
|
||||
if (event.detail && event.detail.language) {
|
||||
console.log('ProgressTracker: Received language change event:', event.detail.language);
|
||||
// The LanguageProvider will automatically handle the translation update
|
||||
// We just need to ensure the component is aware of the change
|
||||
this.handleLanguageChange(event);
|
||||
}
|
||||
};
|
||||
|
||||
// Listen for language changes
|
||||
document.addEventListener('language-changed', this.languageChangeHandler);
|
||||
},
|
||||
mounted() {
|
||||
this.connectToProgressStream();
|
||||
|
||||
// Setup translation composables
|
||||
const { translateSafe } = useTranslationClient();
|
||||
const { translateConstants, getCachedTranslations, getCachedLanguage } = useConstantsTranslation();
|
||||
this.translateSafe = translateSafe;
|
||||
this.translateConstants = translateConstants;
|
||||
this.getCachedTranslations = getCachedTranslations;
|
||||
this.getCachedLanguage = getCachedLanguage;
|
||||
|
||||
// Check if we already have cached translations and apply them
|
||||
const cachedTranslations = this.getCachedTranslations();
|
||||
if (cachedTranslations) {
|
||||
console.log('ProgressTracker: Applying cached translations on mount');
|
||||
this.translatedStatusTexts = { ...cachedTranslations };
|
||||
this.currentLanguage = this.getCachedLanguage();
|
||||
}
|
||||
|
||||
// Luister naar taalwijzigingen
|
||||
this.languageChangeHandler = (event) => {
|
||||
if (event.detail && event.detail.language) {
|
||||
this.handleLanguageChange(event.detail.language);
|
||||
}
|
||||
};
|
||||
document.addEventListener('language-changed', this.languageChangeHandler);
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.disconnectEventSource();
|
||||
|
||||
// Cleanup language change listener
|
||||
// Remove language change event listener
|
||||
if (this.languageChangeHandler) {
|
||||
document.removeEventListener('language-changed', this.languageChangeHandler);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async handleLanguageChange(newLanguage) {
|
||||
console.log('ProgressTracker: Language change to', newLanguage);
|
||||
|
||||
// Skip if same language
|
||||
if (this.currentLanguage === newLanguage) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentLanguage = newLanguage;
|
||||
|
||||
// Define the original Dutch constants
|
||||
const originalTexts = {
|
||||
error: 'Fout bij verwerking',
|
||||
completed: 'Verwerking voltooid',
|
||||
processing: 'Bezig met redeneren...'
|
||||
};
|
||||
|
||||
try {
|
||||
// Use global constants translation with caching
|
||||
const translatedTexts = await this.translateConstants(originalTexts, newLanguage, {
|
||||
context: 'progress_tracker',
|
||||
apiPrefix: this.apiPrefix
|
||||
});
|
||||
|
||||
// Update component state with translated texts
|
||||
this.translatedStatusTexts = translatedTexts;
|
||||
|
||||
console.log('ProgressTracker: Successfully updated status texts for', newLanguage);
|
||||
} catch (error) {
|
||||
console.error('ProgressTracker: Error translating status texts:', error);
|
||||
// Fallback to original Dutch texts
|
||||
this.translatedStatusTexts = originalTexts;
|
||||
handleLanguageChange(event) {
|
||||
if (event.detail && event.detail.language) {
|
||||
console.log(`ProgressTracker: Language changed to ${event.detail.language}`);
|
||||
// The LanguageProvider automatically updates translations through reactive system
|
||||
// Force component update to ensure UI reflects the new translations
|
||||
this.$forceUpdate();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -205,7 +186,7 @@ export default {
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to create EventSource:', error);
|
||||
this.error = 'Kan geen verbinding maken met de voortgangsstream.';
|
||||
this.error = 'Unable to connect to the server SSE stream.';
|
||||
this.connecting = false;
|
||||
}
|
||||
},
|
||||
@@ -343,7 +324,7 @@ export default {
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error parsing specialist error data:', error);
|
||||
this.error = 'Er is een onbekende fout opgetreden.';
|
||||
this.error = 'An unknown error occurred while processing your request.';
|
||||
this.isCompleted = true;
|
||||
this.hasError = true;
|
||||
this.connecting = false;
|
||||
@@ -351,7 +332,7 @@ export default {
|
||||
|
||||
// Emit generic error
|
||||
this.$emit('specialist-error', {
|
||||
message: 'Er is een onbekende fout opgetreden.',
|
||||
message: 'An unknown error occurred while processing your request.',
|
||||
originalError: 'Failed to parse error data',
|
||||
taskId: this.taskId
|
||||
});
|
||||
@@ -360,7 +341,7 @@ export default {
|
||||
|
||||
handleError(event) {
|
||||
console.error('SSE Error event:', event);
|
||||
this.error = 'Er is een fout opgetreden bij het verwerken van updates.';
|
||||
this.error = 'An unknown error occurred while connecting to the server. Please try again later.';
|
||||
this.connecting = false;
|
||||
|
||||
// Try to parse error data
|
||||
|
||||
@@ -49,7 +49,7 @@ const props = defineProps({
|
||||
},
|
||||
initialLanguage: {
|
||||
type: String,
|
||||
default: 'nl'
|
||||
default: 'en'
|
||||
},
|
||||
supportedLanguageDetails: {
|
||||
type: Object,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, onMounted } from 'vue';
|
||||
import { useTranslationClient } from '../js/composables/useTranslation.js';
|
||||
import { useComponentTranslations } from '../js/services/LanguageProvider.js';
|
||||
|
||||
const props = defineProps({
|
||||
originalText: {
|
||||
@@ -26,7 +26,7 @@ const props = defineProps({
|
||||
},
|
||||
currentLanguage: {
|
||||
type: String,
|
||||
default: 'nl'
|
||||
default: 'en'
|
||||
},
|
||||
apiPrefix: {
|
||||
type: String,
|
||||
@@ -34,9 +34,17 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const { translateSafe } = useTranslationClient();
|
||||
const translatedText = ref(props.originalText);
|
||||
const isLoading = ref(false);
|
||||
// Use component translations from provider
|
||||
const originalTexts = computed(() => ({
|
||||
explanation: props.originalText || ''
|
||||
}));
|
||||
|
||||
const { translations, isLoading, error, currentLanguage } = useComponentTranslations(
|
||||
'sidebar_explanation',
|
||||
originalTexts.value
|
||||
);
|
||||
|
||||
const translatedText = computed(() => translations.value.explanation || props.originalText);
|
||||
|
||||
// Render markdown content
|
||||
const renderedExplanation = computed(() => {
|
||||
@@ -52,41 +60,12 @@ const renderedExplanation = computed(() => {
|
||||
}
|
||||
});
|
||||
|
||||
// Watch for language changes
|
||||
watch(() => props.currentLanguage, async (newLanguage) => {
|
||||
await updateTranslation(newLanguage);
|
||||
});
|
||||
|
||||
// Watch for text changes
|
||||
watch(() => props.originalText, async () => {
|
||||
await updateTranslation(props.currentLanguage);
|
||||
});
|
||||
|
||||
const updateTranslation = async (targetLanguage) => {
|
||||
if (!props.originalText || targetLanguage === 'nl') {
|
||||
translatedText.value = props.originalText;
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading.value = true;
|
||||
try {
|
||||
const result = await translateSafe(props.originalText, targetLanguage, {
|
||||
context: 'sidebar_explanation',
|
||||
apiPrefix: props.apiPrefix,
|
||||
fallbackText: props.originalText
|
||||
});
|
||||
|
||||
translatedText.value = result;
|
||||
} catch (error) {
|
||||
console.warn('Sidebar explanation translation failed:', error);
|
||||
translatedText.value = props.originalText;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
updateTranslation(props.currentLanguage);
|
||||
// Watch for text changes to update the provider
|
||||
watch(() => props.originalText, () => {
|
||||
// Update original texts when prop changes
|
||||
originalTexts.value = {
|
||||
explanation: props.originalText || ''
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user