- Translations completed for Front-End, Configs (e.g. Forms) and free text.
- Allowed_languages and default_language now part of Tenant Make iso Tenant - Introduction of Translation into Traicie Selection Specialist
This commit is contained in:
@@ -4,20 +4,20 @@
|
||||
// Anders moet je ervoor zorgen dat MaterialIconManager.js eerder wordt geladen
|
||||
// en iconManager beschikbaar is via window.iconManager
|
||||
|
||||
// Voeg stylesheet toe voor ChatInput-specifieke stijlen
|
||||
const addStylesheet = () => {
|
||||
if (!document.querySelector('link[href*="chat-input.css"]')) {
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = '/static/assets/css/chat-input.css';
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
};
|
||||
// Voeg stylesheet toe voor ChatInput-specifieke stijlen
|
||||
const addStylesheet = () => {
|
||||
if (!document.querySelector('link[href*="chat-input.css"]')) {
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = '/static/assets/css/chat-input.css';
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
};
|
||||
|
||||
// Laad de stylesheet
|
||||
addStylesheet();
|
||||
// Laad de stylesheet
|
||||
addStylesheet();
|
||||
|
||||
export const ChatInput = {
|
||||
export const ChatInput = {
|
||||
name: 'ChatInput',
|
||||
components: {
|
||||
'dynamic-form': window.DynamicForm
|
||||
@@ -29,6 +29,22 @@
|
||||
if (window.iconManager && this.formData && this.formData.icon) {
|
||||
window.iconManager.ensureIconsLoaded({}, [this.formData.icon]);
|
||||
}
|
||||
|
||||
// Maak een benoemde handler voor betere cleanup
|
||||
this.languageChangeHandler = (event) => {
|
||||
if (event.detail && event.detail.language) {
|
||||
this.handleLanguageChange(event);
|
||||
}
|
||||
};
|
||||
|
||||
// Luister naar taalwijzigingen
|
||||
document.addEventListener('language-changed', this.languageChangeHandler);
|
||||
},
|
||||
beforeUnmount() {
|
||||
// Verwijder event listener bij unmount met de benoemde handler
|
||||
if (this.languageChangeHandler) {
|
||||
document.removeEventListener('language-changed', this.languageChangeHandler);
|
||||
}
|
||||
},
|
||||
props: {
|
||||
currentMessage: {
|
||||
@@ -41,7 +57,7 @@
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: 'Typ je bericht hier... (Enter om te verzenden, Shift+Enter voor nieuwe regel)'
|
||||
default: 'Typ je bericht hier... - Enter om te verzenden, Shift+Enter voor nieuwe regel'
|
||||
},
|
||||
maxLength: {
|
||||
type: Number,
|
||||
@@ -103,7 +119,10 @@
|
||||
data() {
|
||||
return {
|
||||
localMessage: this.currentMessage,
|
||||
formValues: {}
|
||||
formValues: {},
|
||||
translatedPlaceholder: this.placeholder,
|
||||
isTranslating: false,
|
||||
languageChangeHandler: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -150,6 +169,56 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleLanguageChange(event) {
|
||||
if (event.detail && event.detail.language) {
|
||||
this.translatePlaceholder(event.detail.language);
|
||||
}
|
||||
},
|
||||
|
||||
async translatePlaceholder(language) {
|
||||
// Voorkom dubbele vertaling
|
||||
if (this.isTranslating) {
|
||||
console.log('Placeholder vertaling al bezig, overslaan...');
|
||||
return;
|
||||
}
|
||||
|
||||
// Zet de vertaling vlag
|
||||
this.isTranslating = true;
|
||||
|
||||
// Gebruik de originele placeholder als basis voor vertaling
|
||||
const originalText = this.placeholder;
|
||||
|
||||
try {
|
||||
// Controleer of TranslationClient beschikbaar is
|
||||
if (!window.TranslationClient || typeof window.TranslationClient.translate !== 'function') {
|
||||
console.error('TranslationClient.translate is niet beschikbaar voor placeholder');
|
||||
return;
|
||||
}
|
||||
|
||||
// Gebruik TranslationClient zonder UI indicator
|
||||
const apiPrefix = window.chatConfig?.apiPrefix || '';
|
||||
const response = await window.TranslationClient.translate(
|
||||
originalText,
|
||||
language,
|
||||
null, // source_lang (auto-detect)
|
||||
'chat_input_placeholder', // context
|
||||
apiPrefix // API prefix voor tenant routing
|
||||
);
|
||||
|
||||
if (response.success) {
|
||||
// Update de placeholder
|
||||
this.translatedPlaceholder = response.translated_text;
|
||||
} else {
|
||||
console.error('Vertaling placeholder mislukt:', response.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fout bij vertalen placeholder:', error);
|
||||
} finally {
|
||||
// Reset de vertaling vlag
|
||||
this.isTranslating = false;
|
||||
}
|
||||
},
|
||||
|
||||
initFormValues() {
|
||||
if (this.formData && this.formData.fields) {
|
||||
console.log('Initializing form values for fields:', this.formData.fields);
|
||||
@@ -300,7 +369,7 @@
|
||||
ref="messageInput"
|
||||
v-model="localMessage"
|
||||
@keydown="handleKeydown"
|
||||
:placeholder="placeholder"
|
||||
:placeholder="translatedPlaceholder"
|
||||
rows="1"
|
||||
:disabled="isLoading"
|
||||
:maxlength="maxLength"
|
||||
|
||||
@@ -52,6 +52,11 @@ export const ChatMessage = {
|
||||
if (window.iconManager && this.message.formData && this.message.formData.icon) {
|
||||
window.iconManager.loadIcon(this.message.formData.icon);
|
||||
}
|
||||
|
||||
// Sla de originele inhoud op voor het eerste bericht als we in een conversatie zitten met slechts één bericht
|
||||
if (this.message.sender === 'ai' && !this.message.originalContent) {
|
||||
this.message.originalContent = this.message.content;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'message.formData.icon': {
|
||||
@@ -69,6 +74,14 @@ export const ChatMessage = {
|
||||
formVisible: true
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// Luister naar taalwijzigingen
|
||||
document.addEventListener('language-changed', this.handleLanguageChange);
|
||||
},
|
||||
beforeUnmount() {
|
||||
// Verwijder event listener bij verwijderen component
|
||||
document.removeEventListener('language-changed', this.handleLanguageChange);
|
||||
},
|
||||
computed: {
|
||||
hasFormData() {
|
||||
return this.message.formData &&
|
||||
@@ -80,6 +93,12 @@ export const ChatMessage = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
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);
|
||||
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
export const LanguageSelector = {
|
||||
name: 'LanguageSelector',
|
||||
props: {
|
||||
initialLanguage: {
|
||||
type: String,
|
||||
default: 'nl'
|
||||
},
|
||||
supportedLanguageDetails: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
allowedLanguages: {
|
||||
type: Array,
|
||||
default: () => ['nl', 'en', 'fr', 'de']
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
availableLanguages() {
|
||||
// Maak een array van taalobjecten op basis van de toegestane talen
|
||||
// en de ondersteunde taaldetails
|
||||
const languages = [];
|
||||
|
||||
// Als er geen toegestane talen zijn of de lijst is leeg, gebruik een standaardlijst
|
||||
const languagesToUse = (this.allowedLanguages && this.allowedLanguages.length > 0)
|
||||
? this.allowedLanguages
|
||||
: ['nl', 'en', 'fr', 'de'];
|
||||
|
||||
// Loop door alle ondersteunde taaldetails
|
||||
if (this.supportedLanguageDetails && Object.keys(this.supportedLanguageDetails).length > 0) {
|
||||
// Vind talen die overeenkomen met toegestane taalcodes
|
||||
for (const [langName, langDetails] of Object.entries(this.supportedLanguageDetails)) {
|
||||
const isoCode = langDetails['iso 639-1'];
|
||||
if (languagesToUse.includes(isoCode)) {
|
||||
languages.push({
|
||||
code: isoCode,
|
||||
name: langName,
|
||||
flag: langDetails.flag || ''
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback als er geen taaldetails beschikbaar zijn
|
||||
const defaultLanguages = {
|
||||
'nl': { name: 'Nederlands', flag: '🇳🇱' },
|
||||
'en': { name: 'English', flag: '🇬🇧' },
|
||||
'fr': { name: 'Français', flag: '🇫🇷' },
|
||||
'de': { name: 'Deutsch', flag: '🇩🇪' }
|
||||
};
|
||||
|
||||
languagesToUse.forEach(code => {
|
||||
if (defaultLanguages[code]) {
|
||||
languages.push({
|
||||
code: code,
|
||||
name: defaultLanguages[code].code,
|
||||
flag: defaultLanguages[code].flag
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log('LanguageSelector: availableLanguages computed:', languages);
|
||||
return languages;
|
||||
}
|
||||
},
|
||||
emits: ['language-changed'],
|
||||
data() {
|
||||
return {
|
||||
selectedLanguage: this.initialLanguage,
|
||||
currentLanguage: this.initialLanguage
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
console.log('LanguageSelector mounted with:', {
|
||||
initialLanguage: this.initialLanguage,
|
||||
selectedLanguage: this.selectedLanguage,
|
||||
availableLanguages: this.availableLanguages
|
||||
});
|
||||
|
||||
// Stuur het language-changed event uit met de initiële taal
|
||||
console.log(`LanguageSelector: Emitting language-changed event for initial language ${this.initialLanguage}`);
|
||||
this.$emit('language-changed', this.initialLanguage);
|
||||
},
|
||||
methods: {
|
||||
changeLanguage(languageCode) {
|
||||
console.log(`LanguageSelector: changeLanguage called with ${languageCode}, current: ${this.currentLanguage}`);
|
||||
|
||||
if (this.currentLanguage !== languageCode) {
|
||||
console.log(`LanguageSelector: Emitting language-changed event for ${languageCode}`);
|
||||
this.currentLanguage = languageCode;
|
||||
this.$emit('language-changed', languageCode);
|
||||
} else {
|
||||
console.log(`LanguageSelector: No change needed, already ${languageCode}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="language-selector">
|
||||
<label for="language-select">Taal / Language:</label>
|
||||
<div class="select-wrapper">
|
||||
<select
|
||||
id="language-select"
|
||||
v-model="selectedLanguage"
|
||||
@change="changeLanguage(selectedLanguage); currentLanguage = selectedLanguage"
|
||||
class="language-select"
|
||||
>
|
||||
<option
|
||||
v-for="lang in availableLanguages"
|
||||
:key="lang.code"
|
||||
:value="lang.code"
|
||||
>
|
||||
{{ lang.flag }} {{ lang.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
};
|
||||
@@ -27,12 +27,21 @@ export const MessageHistory = {
|
||||
data() {
|
||||
return {
|
||||
isAtBottom: true,
|
||||
unreadCount: 0
|
||||
unreadCount: 0,
|
||||
originalFirstMessage: null,
|
||||
isTranslating: false, // Vlag om dubbele vertaling te voorkomen
|
||||
languageChangeHandler: null // Referentie voor cleanup
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.scrollToBottom();
|
||||
this.setupScrollListener();
|
||||
this.listenForLanguageChanges();
|
||||
|
||||
// Sla de originele inhoud van het eerste bericht op als er maar één bericht is
|
||||
if (this.messages.length === 1 && this.messages[0].sender === 'ai') {
|
||||
this.originalFirstMessage = this.messages[0].content;
|
||||
}
|
||||
},
|
||||
updated() {
|
||||
if (this.autoScroll && this.isAtBottom) {
|
||||
@@ -40,6 +49,73 @@ export const MessageHistory = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
listenForLanguageChanges() {
|
||||
// Maak een benoemde handler voor cleanup
|
||||
this.languageChangeHandler = (event) => {
|
||||
if (event.detail && event.detail.language) {
|
||||
this.translateFirstMessageIfNeeded(event.detail.language);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('language-changed', this.languageChangeHandler);
|
||||
},
|
||||
|
||||
async translateFirstMessageIfNeeded(language) {
|
||||
// Voorkom dubbele vertaling
|
||||
if (this.isTranslating) {
|
||||
console.log('Vertaling al bezig, overslaan...');
|
||||
return;
|
||||
}
|
||||
|
||||
// Alleen vertalen als er precies één bericht is en het is van de AI
|
||||
if (this.messages.length === 1 && this.messages[0].sender === 'ai') {
|
||||
const firstMessage = this.messages[0];
|
||||
|
||||
// Controleer of we een origineel bericht hebben om te vertalen
|
||||
const contentToTranslate = this.originalFirstMessage || firstMessage.content;
|
||||
|
||||
// Sla het originele bericht op als we dat nog niet hebben gedaan
|
||||
if (!this.originalFirstMessage) {
|
||||
this.originalFirstMessage = contentToTranslate;
|
||||
}
|
||||
|
||||
// Zet de vertaling vlag
|
||||
this.isTranslating = true;
|
||||
|
||||
try {
|
||||
// Controleer of de vertaalclient beschikbaar is
|
||||
if (!window.TranslationClient || typeof window.TranslationClient.translate !== 'function') {
|
||||
console.error('TranslationClient.translate is niet beschikbaar');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Vertalen van eerste bericht naar ${language}`);
|
||||
|
||||
// Vertaal het bericht met de juiste context
|
||||
const response = await window.TranslationClient.translate(
|
||||
contentToTranslate,
|
||||
language,
|
||||
null, // source_lang (auto-detect)
|
||||
'first_message', // context
|
||||
this.apiPrefix // API prefix voor tenant routing
|
||||
);
|
||||
|
||||
if (response.success) {
|
||||
console.log('Vertaling van eerste bericht voltooid:', response.translated_text);
|
||||
// Update het bericht zonder een indicator te tonen
|
||||
firstMessage.content = response.translated_text;
|
||||
} else {
|
||||
console.error('Vertaling van eerste bericht mislukt:', response.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fout bij het vertalen van eerste bericht:', error);
|
||||
} finally {
|
||||
// Reset de vertaling vlag
|
||||
this.isTranslating = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
scrollToBottom() {
|
||||
const container = this.$refs.messagesContainer;
|
||||
if (container) {
|
||||
@@ -98,6 +174,11 @@ export const MessageHistory = {
|
||||
if (container) {
|
||||
container.removeEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
|
||||
// Cleanup language change listener
|
||||
if (this.languageChangeHandler) {
|
||||
document.removeEventListener('language-changed', this.languageChangeHandler);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="message-history-container">
|
||||
|
||||
Reference in New Issue
Block a user