From 0efb495339bb1829927d2762ee854fb85ea883cd Mon Sep 17 00:00:00 2001 From: Khyretos Date: Thu, 4 Jan 2024 21:58:15 +0100 Subject: [PATCH] Language fixes --- backend/loquendoBot_backend.py | 2 +- src/css/chat.css | 27 ++++--- src/css/menu.css | 45 ++++-------- src/css/tabs.css | 11 +-- src/css/tts-menu.css | 10 +-- src/index.html | 26 ++++--- src/js/backend.js | 72 ++++++++++++++----- src/js/languages.js | 4 +- src/js/renderer.js | 127 ++++++++++++++++++++++----------- src/js/settings.js | 2 +- src/js/twitch.js | 15 ++-- 11 files changed, 210 insertions(+), 131 deletions(-) diff --git a/backend/loquendoBot_backend.py b/backend/loquendoBot_backend.py index 19ba637..58d624b 100644 --- a/backend/loquendoBot_backend.py +++ b/backend/loquendoBot_backend.py @@ -240,7 +240,7 @@ def get_translation(): source=detectedLanguage, target=settings["LANGUAGE"]["TRANSLATE_TO"] ).translate(message) except Exception as e: - return jsonify({"error": e}), 500 + return jsonify({"error": "Could not translate, continuing with next language"}), 500 return jsonify({"translation": translated}), 200 diff --git a/src/css/chat.css b/src/css/chat.css index b06ebd2..da133b0 100644 --- a/src/css/chat.css +++ b/src/css/chat.css @@ -274,7 +274,7 @@ h1 { .username.sender { padding: 0px 5px 5px 30px; - margin: 20px 5px 5px 30px; + margin: 20px 5px 5px 25px; } .username.user { @@ -505,13 +505,20 @@ h1 { background-color: var(--main-color1); } -.emoji-picker { - margin-left: auto; - visibility: hidden; - bottom: 50px; - left: 0px; +.emotes { + position: relative; + cursor: pointer; +} + +.dark { + display: none; position: absolute; z-index: 1; + top: -400px; +} + +.emotes:hover .dark { + display: block; } .fi { @@ -539,11 +546,15 @@ h1 { padding: 0px 0px 0px 0px; margin: -45px 0px 0px -40px; top: 30px; - left: 20px; } .language-icon { position: relative; top: 45px; - left: 20px; +} + +.flag-icon { + width: 20px !important; + height: 20px !important; + left: 18px; } diff --git a/src/css/menu.css b/src/css/menu.css index 7efc7f9..c874a9a 100644 --- a/src/css/menu.css +++ b/src/css/menu.css @@ -61,11 +61,6 @@ color: var(--main-color2); } -.hdp:hover { - position: fixed; - /* filter: brightness(150%); */ -} - .menu .items .item-active { background: -webkit-linear-gradient(left, var(--main-color2) 10%, var(--main-color2), var(--main-color1) 10%, var(--main-color1) 10%); color: var(--main-color2); @@ -229,60 +224,50 @@ height: 100%; } -.btn { - background-color: blue; - color: red; - padding: 16px; - font-size: 16px; - border: none; - cursor: pointer; -} .pop { position: relative; - display: inline-block; + cursor: pointer; } -.pop.up { +.pop-selection { + width: 20px !important; + height: 20px !important; +} + +.miniText { + position: absolute; + font-size: 8pt; + color: white; + padding: 3px; } .pop-content { display: none; position: absolute; - background-color: black; + background-color: var(--main-color3); z-index: 1; height: 400px; width: max-content; overflow: auto; - display: grid; grid-template-columns: repeat(3, 1fr); top: -400px; color: white; + border: 1px solid #444; } pop-content div { color: white; - padding: 12px 16px; text-decoration: none; display: block; } .pop-content div:hover { - display: none; - /* background-color: black; */ + backdrop-filter: invert(50%); } .pop:hover .pop-content { display: grid; - /* display: none; */ grid-template-columns: repeat(3, 1fr); - /* display: block; */ -} -.pop:hover .btn { - background-color: blue; } .language-select { - margin: 5px; + padding: 5px; position: relative; } - -.language-select:hover { - background-color: blue; -} diff --git a/src/css/tabs.css b/src/css/tabs.css index 26fef88..32dda3d 100644 --- a/src/css/tabs.css +++ b/src/css/tabs.css @@ -377,22 +377,17 @@ input[type='lol'] { .tooltip { position: absolute; - display: inline-block; - visibility: hidden; - font-size: 12px; - line-height: 20px; + font-size: 12pt; padding: 5px; background: var(--main-color3); border-radius: 5px; visibility: hidden; - opacity: 1; box-shadow: -2px 2px 5px rgba(0, 0, 0, 0.2); - transition: - opacity 0.3s, - visibility 0s; color: var(--main-color2); font-family: 'xxii_avenmedium'; z-index: 999; + max-width: 200px; + width: max-content; } div[type='text']:disabled { diff --git a/src/css/tts-menu.css b/src/css/tts-menu.css index 77f8b99..60284d9 100644 --- a/src/css/tts-menu.css +++ b/src/css/tts-menu.css @@ -78,24 +78,18 @@ textarea { 0 0 5px #070607, 0 0 5px #070607, 0 0 5px #070607; - /* transition: all 0.15s ease-in-out; */ + transition: all 0.15s ease-in-out; text-align: center; } .SmallButton:hover { - /* color: var(--main-color1); */ - width: 50px; + color: var(--main-color1); cursor: pointer; - /* filter: brightness(150%); */ } .SmallButton:active { color: var(--main-color1); transform: translateY(4px); - text-shadow: - 0 0 5px #000, - 0 0 5px #000, - 0 0 5px #000; } .AdvancedMenuButton { diff --git a/src/index.html b/src/index.html index be520bf..c9c820e 100644 --- a/src/index.html +++ b/src/index.html @@ -44,13 +44,13 @@
-
+
-
+
-
+
@@ -577,13 +577,21 @@
-
+
+
- -
+
+
In
+ +
+
+
+
Out
@@ -697,7 +705,7 @@
-
+
diff --git a/src/js/backend.js b/src/js/backend.js index 751deb5..b2d318a 100644 --- a/src/js/backend.js +++ b/src/js/backend.js @@ -47,6 +47,10 @@ async function getInstalledVoices() { function setTranslatedMessage(message) { if (message.language.selectedLanguage.ISO639 !== message.language.detectedLanguage.ISO639) { const messageBox = document.getElementById(message.messageId).getElementsByClassName('msg-box')[0]; + const languageBox = document.getElementById(message.messageId).getElementsByClassName('language-icon flag-icon')[0]; + + languageBox.classList = `fi fi-${message.language.detectedLanguage.ISO3166} fis language-icon flag-icon`; + languageBox.setAttribute('tip', message.language.detectedLanguage.name); const translationHeader = document.createElement('div'); translationHeader.className = 'translation-header'; @@ -57,7 +61,7 @@ function setTranslatedMessage(message) { translationIcon.className = 'translation-icon'; const languageElement = document.createElement('span'); const language = getLanguageProperties(settings.LANGUAGE.TRANSLATE_TO); - languageElement.classList = `fi fi-${message.language.selectedLanguage.ISO3166} fis`; + languageElement.classList = `fi fi-${message.language.selectedLanguage.ISO3166} fis flag-icon`; languageElement.setAttribute('tip', message.language.selectedLanguage.name); addSingleTooltip(languageElement); translationIcon.appendChild(languageElement); @@ -80,6 +84,7 @@ function setTranslatedMessage(message) { language: message.language }); } + return message.language.detectedLanguage; } async function getTranslatedMessage(message) { @@ -90,16 +95,23 @@ async function getTranslatedMessage(message) { }, body: JSON.stringify({ message: message.message, + remainder: message.remainingDetectedLanguages, language: message.language.detectedLanguage.IETF }) // Convert the data to JSON and include it in the request body }; try { const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/translate`, requestOptions); + const responseData = await response.json(); if (response.ok) { - const responseData = await response.json(); - console.log('Translated message:', responseData); + + if (settings.LANGUAGE.BROADCAST_TRANSLATION) { + twitch.sendMessage( + `[${message.language.detectedLanguage.name} ${message.language.detectedLanguage.ISO639} > ${message.language.selectedLanguage.name} ${message.language.selectedLanguage.ISO639}] @${message.username}: ${responseData.translation}` + ); + } + setTranslatedMessage({ originalMessage: message.message, translation: responseData.translation, @@ -109,38 +121,65 @@ async function getTranslatedMessage(message) { username: message.username, logoUrl: message.logoUrl }); - if (settings.LANGUAGE.BROADCAST_TRANSLATION) { - twitch.sendMessage( - `[${message.language.detectedLanguage.name} ${message.language.detectedLanguage.ISO639} > ${message.language.selectedLanguage.name} ${message.language.selectedLanguage.ISO639}] @${message.username}: ${responseData.translation}` - ); - } + return message.language.detectedLanguage; } else { - console.error('Failed to send termination signal to Flask server.'); - message.message = 'Error,could not translate message'; - message.languaga = 'en-GB'; - getTranslatedMessage(message); + console.error(responseData); + if (message.remainingDetectedLanguages.length > 0) { + message.language.detectedLanguage = getLanguageProperties(message.remainingDetectedLanguages[0]); + message.remainingDetectedLanguages.shift(); + return getTranslatedMessage(message); + } else { + message.message = 'Error, Could not translate message'; + message.language.detectedLanguage = getLanguageProperties('en-GB'); + return getTranslatedMessage(message); + } } } catch (error) { console.error('Error sending termination signal:', error); + message.message = 'Error, Could not translate message'; + message.language.detectedLanguage = getLanguageProperties('en-GB'); + getTranslatedMessage(message); } } -function filterLanguage(message) { +async function filterLanguage(message) { const selectedPrimaryLanguage = getLanguageProperties(settings.LANGUAGE.TRANSLATE_TO); const selectedPrimaryLanguageIndex = message.languages.indexOf(selectedPrimaryLanguage.ISO639) === -1 ? 99 : message.languages.indexOf(selectedPrimaryLanguage.ISO639); + const selectedSecondaryLanguage = getLanguageProperties(settings.TTS.SECONDARY_TTS_LANGUAGE); const selectedSecondaryLanguageIndex = message.languages.indexOf(selectedSecondaryLanguage.ISO639) === -1 ? 99 : message.languages.indexOf(selectedSecondaryLanguage.ISO639); - const detectedLanguage = getLanguageProperties(message.languages[0]); + + let detectedLanguage = ''; + const remainingDetectedLanguages = []; + const detectedLanguages = message.languages.slice(); + + for (const [index, language] of detectedLanguages.entries()) { + detectedLanguage = getLanguageProperties(language); + + if (detectedLanguage !== 'error') { + detectedLanguages.splice(index, 1); + break; + } + } + + for (const [index, language] of detectedLanguages.entries()) { + const remainderLanguage = getLanguageProperties(language); + if (remainderLanguage !== 'error') { + remainingDetectedLanguages.push(remainderLanguage.IETF); + } + } + const language = selectedPrimaryLanguageIndex < selectedSecondaryLanguageIndex ? selectedPrimaryLanguage : detectedLanguage; if (settings.LANGUAGE.TRANSLATE_TO !== 'none' && selectedPrimaryLanguage.ISO639 !== detectedLanguage.ISO639) { getTranslatedMessage({ message: message.message, messageId: message.messageId, + remainingDetectedLanguages, language: { selectedLanguage: selectedPrimaryLanguage, - detectedLanguage + detectedLanguage: detectedLanguage }, username: message.username, formattedMessage: message.formattedMessage, @@ -160,6 +199,7 @@ function filterLanguage(message) { logoUrl: message.logoUrl }); } + return language; } @@ -182,7 +222,7 @@ async function getDetectedLanguage(message) { const responseData = await response.json(); console.log('Detected Languages:', responseData); - return filterLanguage({ + return await filterLanguage({ languages: responseData.languages, message: message.message, messageId: message.messageId, diff --git a/src/js/languages.js b/src/js/languages.js index fa95e2f..8aaed9f 100644 --- a/src/js/languages.js +++ b/src/js/languages.js @@ -21,8 +21,8 @@ const languages = { amharic: { IETF: 'am-ET', ISO639: 'am', ISO3166: 'et' }, 'antigua and barbuda creole english': { IETF: 'aig-AG', ISO639: 'aig', ISO3166: 'ag' }, arabic: { IETF: 'ar-SA', ISO639: 'ar', ISO3166: 'sa' }, - 'arabic egyptian': { IETF: 'ar-EG', ISO639: 'ar', ISO3166: 'eg' }, - // aragonese: { IETF: 'an-ES', ISO639: 'an', ISO3166: 'es' }, + 'arabic egyptian': { IETF: 'ar-EG', ISO639: 'arz', ISO3166: 'eg' }, + aragonese: { IETF: 'es-ES', ISO639: 'an', ISO3166: 'es' }, armenian: { IETF: 'hy-AM', ISO639: 'hy', ISO3166: 'am' }, assamese: { IETF: 'as-IN', ISO639: 'as', ISO3166: 'in' }, asturian: { IETF: 'ast-ES', ISO639: 'ast', ISO3166: 'es' }, diff --git a/src/js/renderer.js b/src/js/renderer.js index d4e6a4c..6fbe662 100644 --- a/src/js/renderer.js +++ b/src/js/renderer.js @@ -163,8 +163,25 @@ async function getAudioDevices() { getAudioDevices(); -function setLanguagesinSelectx() { - const languageSelect = document.querySelector('.pop-content'); // obtain the html reference of the google voices comboBox +function setSelectedLanguageinSelect(languageSelect, language) { + const button = languageSelect.querySelector('.SmallButton'); + const languageElement = document.createElement('span'); + languageElement.classList = `fi fi-${language.ISO3166} fis pop-selection`; + languageElement.setAttribute('tip', language.name); + button.innerHTML = ''; + button.appendChild(languageElement); + addSingleTooltip(languageElement); +} + +function setLanguagesinSelectx(languageSelector, language) { + const languageSelect = document.querySelector(languageSelector); // obtain the html reference of the google voices comboBox + const languageSelectContent = languageSelect.querySelector('.pop-content'); + + languageSelectContent.addEventListener('click', e => { + console.log(e.target); + language = getLanguageProperties(e.target.getAttribute('value')); + setSelectedLanguageinSelect(languageSelect, language); + }); for (const language in languageObject.languages) { if (Object.prototype.hasOwnProperty.call(languageObject.languages, language)) { @@ -177,24 +194,27 @@ function setLanguagesinSelectx() { const languageElement = document.createElement('span'); languageElement.classList = `fi fi-${ISO3166} fis`; + languageElement.style.pointerEvents = 'none'; option.setAttribute('tip', language); const text = document.createElement('span'); + text.style.pointerEvents = 'none'; text.innerHTML = ` - ${ISO639}`; - option.value = IETF; + option.setAttribute('value', IETF); - languageSelect.appendChild(option); + languageSelectContent.appendChild(option); option.appendChild(languageElement); option.appendChild(text); addSingleTooltip(option); } } - // languageSelect.selectedIndex = setting; + setSelectedLanguageinSelect(languageSelect, language); } -setLanguagesinSelectx(); +setLanguagesinSelectx('.pop.in', getLanguageProperties(settings.LANGUAGE.SEND_TRANSLATION_IN)); +setLanguagesinSelectx('.pop.out', getLanguageProperties(settings.LANGUAGE.SEND_TRANSLATION_OUT)); function setLanguagesinSelect(languageSelector, setting) { const languageSelect = document.querySelector(languageSelector); // obtain the html reference of the google voices comboBox @@ -232,6 +252,38 @@ function addVoiceService(name) { addToselect('#secondaryTTSService'); } +function determineTootlTipPosition(element) { + const horizontal = document.body.clientWidth / 2; + const vertical = document.body.clientHeight / 2; + + element.tip.style.left = `${element.mouse.x}px`; + element.tip.style.top = `${element.mouse.y}px`; + + const tipPosition = element.tip.getBoundingClientRect(); + + if (element.position.x < horizontal && element.position.y < vertical) { + element.tip.style.top = `${parseInt(element.tip.style.top) + 25}px`; + element.tip.style.left = `${parseInt(element.tip.style.left) + 10}px`; + } + + if (element.position.x < horizontal && element.position.y > vertical) { + element.tip.style.top = `${parseInt(element.tip.style.top) - tipPosition.height}px`; + element.tip.style.left = `${parseInt(element.tip.style.left) + 10}px`; + } + + if (element.position.x > horizontal && element.position.y < vertical) { + element.tip.style.top = `${parseInt(element.tip.style.top) + 25}px`; + element.tip.style.left = `${parseInt(element.tip.style.left) - tipPosition.width}px`; + } + + if (element.position.x > horizontal && element.position.y > vertical) { + element.tip.style.top = `${parseInt(element.tip.style.top) - tipPosition.height}px`; + element.tip.style.left = `${parseInt(element.tip.style.left) - tipPosition.width}px`; + } + + element.tip.style.visibility = 'visible'; +} + // Small tooltip function addSingleTooltip(el) { const tip = document.createElement('div'); @@ -244,14 +296,14 @@ function addSingleTooltip(el) { image.src = el.src; tip.appendChild(image); } - tip.style.transform = `translate(${el.hasAttribute('tip-left') ? 'calc(-100% - 5px)' : '15px'}, ${ - el.hasAttribute('tip-top') ? '-100%' : '15px' - })`; body.appendChild(tip); + tip.pointerEvents = 'none'; element.onmousemove = e => { - tip.style.left = `${e.x}px`; - tip.style.top = `${e.y}px`; - tip.style.visibility = 'visible'; + determineTootlTipPosition({ + position: element.getBoundingClientRect(), + mouse: { x: e.x, y: e.y }, + tip + }); }; element.onmouseleave = e => { tip.style.visibility = 'hidden'; @@ -270,7 +322,7 @@ function showChatMessage(article) { const messages = document.body.querySelectorAll('.msg-container'); const lastMessage = messages[messages.length - 1]; - lastMessage.scrollIntoView(); + lastMessage.scrollIntoView({ block: 'end', behavior: 'smooth' }); } function getPostTime() { @@ -338,33 +390,28 @@ if (fs.existsSync(emoteListSavePath)) { } function getLanguageProperties(languageToDetect) { - const filteredLanguage = Object.keys(languageObject.languages).reduce(function (accumulator, currentValue) { - if ( - languageObject.languages[currentValue].IETF === languageToDetect || - languageObject.languages[currentValue].ISO639 === languageToDetect || - languageObject.languages[currentValue].ISO3166 === languageToDetect - ) { - accumulator[currentValue] = languageObject.languages[currentValue]; - } - return accumulator; - }, {}); + try { + const filteredLanguage = Object.keys(languageObject.languages).reduce(function (accumulator, currentValue) { + if ( + languageObject.languages[currentValue].IETF === languageToDetect || + languageObject.languages[currentValue].ISO639 === languageToDetect || + languageObject.languages[currentValue].ISO3166 === languageToDetect + ) { + accumulator[currentValue] = languageObject.languages[currentValue]; + } + return accumulator; + }, {}); - const language = { - name: Object.getOwnPropertyNames(filteredLanguage)[0], - ISO3166: filteredLanguage[Object.keys(filteredLanguage)[0]].ISO3166, - ISO639: filteredLanguage[Object.keys(filteredLanguage)[0]].ISO639, - IETF: filteredLanguage[Object.keys(filteredLanguage)[0]].IETF - }; + const language = { + name: Object.getOwnPropertyNames(filteredLanguage)[0], + ISO3166: filteredLanguage[Object.keys(filteredLanguage)[0]].ISO3166, + ISO639: filteredLanguage[Object.keys(filteredLanguage)[0]].ISO639, + IETF: filteredLanguage[Object.keys(filteredLanguage)[0]].IETF + }; - return language; -} - -document.body.querySelector('#emojis').addEventListener('click', () => { - emojiPicker.style.visibility === 'visible' ? (emojiPicker.style.visibility = 'hidden') : (emojiPicker.style.visibility = 'visible'); -}); - -document.body.addEventListener('click', e => { - if (e.target.id !== 'emojis' && e.target.nodeName !== 'EMOJI-PICKER' && emojiPicker.style.visibility === 'visible') { - emojiPicker.style.visibility = 'hidden'; + return language; + } catch (e) { + // console.error(error); + return 'error'; } -}); +} diff --git a/src/js/settings.js b/src/js/settings.js index 40ffea2..a6c99af 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -752,7 +752,7 @@ document.body.querySelector('#ZOOMLEVEL').addEventListener('change', () => { }); document.body.querySelector('emoji-picker').addEventListener('emoji-click', e => { - console.log(e.detail); + // console.log(e.detail); const div = document.getElementById('textInput'); if (e.detail.unicode === undefined) { div.value += e.detail.name + ' '; diff --git a/src/js/twitch.js b/src/js/twitch.js index fc60778..bc9d74a 100644 --- a/src/js/twitch.js +++ b/src/js/twitch.js @@ -133,17 +133,18 @@ async function displayTwitchMessage(logoUrl, username, messageObject, filteredMe } }); } + + showChatMessage(article); + if (settings.LANGUAGE.USE_DETECTION) { await backend.getDetectedLanguage({ message: filteredMessage, messageId, username, logoUrl, formattedMessage }).then(language => { + console.log(language); const languageElement = document.createElement('span'); - languageElement.classList = `fi fi-${language.ISO3166} fis language-icon`; + languageElement.classList = `fi fi-${language.ISO3166} fis language-icon flag-icon`; languageElement.setAttribute('tip', language.name); article.appendChild(languageElement); addSingleTooltip(languageElement); - // Appends the message to the main chat box (shows the message) - showChatMessage(article); - if (filteredMessage && !settings.LANGUAGE.OUTPUT_TO_TTS) { sound.playVoice({ filteredMessage, @@ -154,16 +155,14 @@ async function displayTwitchMessage(logoUrl, username, messageObject, filteredMe }); } - window.article = article; + // window.article = article; }); } else { - showChatMessage(article); - if (filteredMessage) { sound.playVoice({ filteredMessage, logoUrl, username, formattedMessage }); } - window.article = article; + // window.article = article; } sound.playNotificationSound();