320 lines
12 KiB
HTML
320 lines
12 KiB
HTML
<!DOCUMENT html>
|
|
<html lang="br">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Tradutor simultâneo</title>
|
|
<style>
|
|
body {
|
|
font-family: sans-serif;
|
|
background-color: black;
|
|
color: white;
|
|
}
|
|
dl#transcriptions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
dl#transcriptions>dt {
|
|
display: block;
|
|
max-width: 4rem;
|
|
flex: 0 0 4rem;
|
|
border-right: 1px solid white;
|
|
border-bottom: 1px solid white;
|
|
}
|
|
dl#transcriptions>dd {
|
|
margin-inline-start: 4em;
|
|
max-width: calc( 100% - 9rem );
|
|
flex: 0 0 calc( 100% - 9rem );
|
|
height: 3.4em;
|
|
overflow-y: hidden;
|
|
display: flex;
|
|
flex-direction: column-reverse;
|
|
font-size: 3em;
|
|
font-weight: bold;
|
|
}
|
|
dl#transcriptions>dt, dl#transcriptions>dd {
|
|
align-items: baseline;
|
|
margin: 1rem;
|
|
margin-top: 0.5rem;
|
|
}
|
|
form {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
.nospacing {
|
|
margin: 0px;
|
|
padding: 0px;
|
|
}
|
|
.formgroup {
|
|
padding-left: 1rem;
|
|
padding-right: 1rem;
|
|
border-right: 1px solid white;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div>
|
|
<div id="cfgformp">
|
|
<h3 class="nospacing">Configurações</h3>
|
|
<form id="cfgform" onsubmit="return false;">
|
|
<div class="formgroup">
|
|
<h5 class="nospacing">Idioma da fala</h5>
|
|
<input type="radio" id="ilpt" name="il" value="0" checked>
|
|
<label for="ilpt">PT</label><br>
|
|
<input type="radio" id="ilen" name="il" value="1">
|
|
<label for="ilen">EN</label><br>
|
|
<input type="radio" id="iles" name="il" value="2">
|
|
<label for="iles">ES</label><br>
|
|
</div>
|
|
<div class="formgroup">
|
|
<h5 class="nospacing">Idioma da 1ª tradução</h5>
|
|
<input type="radio" id="1lpt" name="1l" value="0">
|
|
<label for="1lpt">PT</label><br>
|
|
<input type="radio" id="1len" name="1l" value="1">
|
|
<label for="1len">EN</label><br>
|
|
<input type="radio" id="1les" name="1l" value="2">
|
|
<label for="1les">ES</label><br>
|
|
<input type="radio" id="1l_" name="1l" value="-1" checked>
|
|
<label for="1l_">Ignorar</label><br>
|
|
</div>
|
|
<div class="formgroup">
|
|
<h5 class="nospacing">Idioma da 2ª tradução</h5>
|
|
<input type="radio" id="2lpt" name="2l" value="0">
|
|
<label for="2lpt">PT</label><br>
|
|
<input type="radio" id="2len" name="2l" value="1">
|
|
<label for="2len">EN</label><br>
|
|
<input type="radio" id="2les" name="2l" value="2">
|
|
<label for="2les">ES</label><br>
|
|
<input type="radio" id="2l_" name="2l" value="-1" checked>
|
|
<label for="2l_">Ignorar</label><br>
|
|
</div>
|
|
<div class="formgroup">
|
|
<h5 class="nospacing">Controle</h5>
|
|
<input type="button" value="Aplicar" onclick="return aplicar();">
|
|
</div>
|
|
</form>
|
|
<hr>
|
|
</div>
|
|
<div class="loader">
|
|
<h2>Configure antes de usar</h2>
|
|
<hr>
|
|
</div>
|
|
<dl id="transcriptions">
|
|
<dt id="i1dt">fala</dt>
|
|
<dd id="i1dd">
|
|
<div>
|
|
<span class="output"></span>
|
|
<span class="listened"></span>
|
|
<span class="preview"></span>
|
|
</div>
|
|
</dd>
|
|
<dt id="o1dt">trad1</dt>
|
|
<dd id="o1dd"><div class="translated1"></div></dd>
|
|
<dt id="o2dt">trad2</dt>
|
|
<dd id="o2dd"><div class="translated2"></div></dd>
|
|
</dl>
|
|
<hr>
|
|
</div>
|
|
</body>
|
|
<script defer>
|
|
function build_g_trans_url(from, to, text){
|
|
text = encodeURIComponent(text || '');
|
|
if (text == '')
|
|
return '';
|
|
to = encodeURIComponent(to || 'en');
|
|
from = encodeURIComponent(from || 'auto');
|
|
return (
|
|
'http://translate.googleapis.com/translate_a/single?client=gtx' +
|
|
`&sl=${from}&tl=${to}&dt=t&q=${text}`);
|
|
}
|
|
function doXhr(method, URL, onsuccess, onfailure, body) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open(method, URL);
|
|
xhr.onload = function() {
|
|
if (xhr.status != 200)
|
|
onfailure(xhr);
|
|
else
|
|
onsuccess(xhr);
|
|
};
|
|
xhr.onerror = () => onfailure(xhr);
|
|
xhr.send(body);
|
|
return xhr;
|
|
}
|
|
|
|
function translate(from, to, text, callbackok, callbackerr){
|
|
return doXhr(
|
|
'GET',
|
|
build_g_trans_url(from, to, text),
|
|
callbackok,
|
|
callbackerr);
|
|
}
|
|
|
|
window.SpeechRecognition = window.webkitSpeechRecognition || window.SpeechRecognition;
|
|
if (!'SpeechRecognition' in window) {
|
|
alert("SpeechRecognition is missing")
|
|
}
|
|
|
|
cooldown_time = 5000;
|
|
cooling_down = false;
|
|
LANGS_1 = ['pt', 'en', 'es'];
|
|
LANGS_2 = ['pt-BR', 'en-US', 'es-AR'];
|
|
SPOKEN_LANG_POS = 0;
|
|
SELECTED_LANG1_POS = 1;
|
|
SELECTED_LANG2_POS = 2;
|
|
|
|
recognizing = false;
|
|
recognition = new Object();
|
|
recognition.continuous = false;
|
|
recognition.interimResults = true;
|
|
recognition.lang = LANGS_2[SPOKEN_LANG_POS];
|
|
|
|
from_lang = LANGS_1[SPOKEN_LANG_POS];
|
|
to_lang1 = LANGS_1[SELECTED_LANG1_POS];
|
|
to_lang2 = LANGS_1[SELECTED_LANG2_POS];
|
|
|
|
loader = document.querySelector('.loader');
|
|
diagnostic = document.querySelector('.output');
|
|
listened = document.querySelector('.listened');
|
|
preview = document.querySelector('.preview');
|
|
translated1 = document.querySelector('.translated1');
|
|
translated2 = document.querySelector('.translated2');
|
|
cfgform = document.querySelector('#cfgform');
|
|
cfgformp = document.querySelector('#cfgformp');
|
|
bg = document.querySelector('html');
|
|
|
|
|
|
latest_parts = ['', '', ''];
|
|
|
|
recognition.onstart = function() {
|
|
recognizing = true;
|
|
console.log('onstart');
|
|
}
|
|
recognition.onerror = function(event) {
|
|
console.log('onerror', event);
|
|
aplicar();
|
|
}
|
|
recognition.onend = function() {
|
|
recognizing = false;
|
|
console.log('onend');
|
|
aplicar();
|
|
}
|
|
recognition.onresult = function(event) {
|
|
pdata = '';
|
|
ldata = '';
|
|
fdata = '';
|
|
for (var i = event.resultIndex; i < event.results.length; ++i) {
|
|
var data = event.results[i][0].transcript;
|
|
if (event.results[i].isFinal) {
|
|
fdata += data;
|
|
} else {
|
|
if (i==0)
|
|
ldata += data;
|
|
else
|
|
pdata += data;
|
|
}
|
|
}
|
|
latest_parts[2] = pdata;
|
|
latest_parts[1] = ldata;
|
|
if (fdata!='') {
|
|
latest_parts[0] = fdata;
|
|
}
|
|
preview.textContent = latest_parts[2];
|
|
listened.textContent = latest_parts[1];
|
|
diagnostic.textContent = latest_parts[0];
|
|
lastest_words = (
|
|
latest_parts
|
|
.join(' ')
|
|
.split(' ')
|
|
.filter(x=>x.length)
|
|
.splice(-20)
|
|
.join(' ')
|
|
);
|
|
rodar_traducao(()=>{
|
|
if (from_lang===null) {
|
|
translated1.innerText = '';
|
|
translated2.innerText = '';
|
|
} else {
|
|
if (from_lang == to_lang1) {
|
|
translated1.innerText = lastest_words;
|
|
} else if (to_lang1===null){
|
|
translated1.innerText = '';
|
|
} else {
|
|
translate(
|
|
from_lang,
|
|
to_lang1,
|
|
lastest_words,
|
|
(xhr)=>{
|
|
var translated = get_first_while_array(
|
|
JSON.parse(xhr.responseText)
|
|
);
|
|
translated2.innerText = translated;
|
|
}
|
|
)
|
|
}
|
|
if (from_lang == to_lang2) {
|
|
translated2.innerText = lastest_words;
|
|
} else if (to_lang2===null){
|
|
translated2.innerText = '';
|
|
} else {
|
|
translate(
|
|
from_lang,
|
|
to_lang2,
|
|
lastest_words,
|
|
(xhr)=>{
|
|
var translated = get_first_while_array(
|
|
JSON.parse(xhr.responseText)
|
|
);
|
|
translated2.innerText = translated;
|
|
}
|
|
)
|
|
}
|
|
}
|
|
});
|
|
}
|
|
function get_first_while_array(a) {
|
|
if (Array.isArray(a))
|
|
return get_first_while_array(a[0]);
|
|
else
|
|
return a;
|
|
}
|
|
function aplicar_conf() {
|
|
newvalues = Object.fromEntries(
|
|
Array.from(
|
|
cfgform.querySelectorAll(':checked')
|
|
).map(x=>[x.name, parseInt(x.value)])
|
|
)
|
|
// cfgformp.style.display = 'none';
|
|
loader.style.display = 'none';
|
|
// console.log(newvalues)
|
|
SPOKEN_LANG_POS = newvalues['il']
|
|
SELECTED_LANG1_POS = newvalues['1l']
|
|
SELECTED_LANG2_POS = newvalues['2l']
|
|
from_lang = LANGS_1[SPOKEN_LANG_POS] || null;
|
|
to_lang1 = LANGS_1[SELECTED_LANG1_POS] || null;
|
|
to_lang2 = LANGS_1[SELECTED_LANG2_POS] || null;
|
|
if (from_lang === null) return;
|
|
recognition_old = recognition;
|
|
recognition = new SpeechRecognition();
|
|
recognition.lang = LANGS_2[SPOKEN_LANG_POS] || null;
|
|
recognition.onstart = recognition_old.onstart;
|
|
recognition.onerror = recognition_old.onerror;
|
|
recognition.onend = recognition_old.onend;
|
|
recognition.onresult = recognition_old.onresult;
|
|
recognition.continuous = recognition_old.continuous;
|
|
recognition.interimResults = recognition_old.interimResults;
|
|
recognition_old.onend = null;
|
|
recognition_old.onerror = null;
|
|
// recognition_old.stop();
|
|
}
|
|
function aplicar(){
|
|
aplicar_conf();
|
|
recognition.start();
|
|
}
|
|
function rodar_traducao(callback){
|
|
if (!cooling_down) {
|
|
cooling_down = true;
|
|
setTimeout(()=>{cooling_down = false;}, cooldown_time);
|
|
callback();
|
|
}
|
|
}
|
|
</script>
|
|
</html> |