Cum pot sa fac sa se vada traducerea fiecarui cuvant dintr-un text cand tin mouse-ul deasupra lui?

Salutare tuturor

Am un site cu texte in romana traduse in engleza. Vreau insa ca utilizatorul sa poata tine mouseul deasupra unui cuvant si sa vada exact traducerea acelui cuvant, traducere pe care as vrea s-o introduc eu, nu printr-un dictionar automat. Stiu ca se poate cu atributul title dar ar lua secole sa il pun la fiecare cuvant in parte. Exista pe wordpress un plugin care adauga hover la texte dar o face global, pentru orice instanta a cuvantului in site, si nici asa nu e bine, as vrea sa o pot face pentru fiecare pagina in parte.
As vrea sa pot face ce au facut cei care au facut site-ul asta: http://www.umich.edu/~turkish/links/mouseover/gizlimabet/gizlimabet.html
Ma poate ajuta cineva? Macar sa-mi zica daca se poate sau visez cai verzi pe pereti.

Poti vedea codul sursa din moment ce este javascript.

<a href="gizlimabet.html"onmouseover="stm(Text[1003],Style[12])"onmouseout="htm()"class="style3">Sermet</a>

javascript

Text[1003]=["<b><font color=#DCDED1 size=1>DICTIONARY FORM:</font></b> <i>Sermet</i><br><b><font color=#DCDED1 size=1>TYPE OF WORD:</font></b> proper noun (Arabic)","<b><font color=#C10000>English</font></b> Sermet (name of a friend of the person by whom the story is given)"]

Nu stiu eu foarte mult javascript, dar din cate vad pe pagina aia are trigger la fiecare cuvant, la onmouseover iti adauga codul html cu chenarul acela care contine traducerea.

Dar are vreo 8000 de cuvinte doar pe pagina aia. Cat o fi stat sa le scrie pe toate… ?

1 Like

Exemplul dat de noah este rudimentar. Probabil că autorul paginii gizlimabet.html a vrut sa testeze tehnici javascript.
În primul rând trebuie modificat enunțul astfel - la trecere mouse peste o propoziție să apară traducerea în engleză(pentru că asocierea cuvânt cu cuvânt produce confuzie - vezi la textul turcesc tradus în engleză)

Problema se rezolvă elegant astfel:
Se creaza o pagină html cu două taguri textarea,

  • unul cu textul în limba română în formatul [1]propoziție1[2]propoziție2… și
  • altul cu textul în limba engleză în formatul [1]propoziție1tradusă[2]propoziție2tradusă
    În html la sfârșit se adaugă un script javascript ce formatează textul din primul tag textarea adăugând taguri span cu onmouseover ce trimite la al doilea tag textarea.

Dacă se acceptă modificarea enunțului și s-a înțeles tehnica revin cu scriptul complet.
Adaug observația că o problemă greșit enunțată nu poate avea o rezolvare practică corectă!

asta-i rezlovare eleganta?

1 Like

@alescx: Decât sa strâmbi din nas mai bine arată ce nu e bine!
Dacă nu ai un răspuns pentru Radu_Lefter lasă-te păgubaș!
Răspunde, vrei să vezi pagina completă cu script cu tot?

n-am nici o solutie buna pentru problema lui radu. nici n-am inteles bine ce vrea. vrea toate cuvintele traduse? vrea doar anumite cuvinte? exista cazuri in care un cuvant poate fi tradus diferit in functie de context?
dar asta nu ma opreste sa observ ca tu ai dat la o parte cerintele lui si ai venit cu o solutie extrem de proasta. de ce textarea? de ce formatul ala extrem de tampit pe care tre sa-l parsezi? ce faci, parsezi in js textul din texarea1 si-l bagi unde? daca textul e formatat ce faci?

daca vrea toate cuvintele traduse:
ce-ar putea incerca e un dictonar gen {‘cuvant’:‘traducere’} (ca-l scrie manual sau vine din backend e irelevant) si un script care sa parseze html-ul si sa puna cuvintele care le gaseste in dictionar intr-un span cu un mouseover pe el. ceva de genul: translate(this). si esti mult mai aproape de exemplul ala “rudimentar”. pentru ca poti adauga mai multe atribute unui cuvant. poti da mai multe detalii la un mouseover

@alescx: Bine că m-ai băgat în seamă! De acord cu observațiile tale! M-am cam repezit să dau o soluție. Insist și eu ca @Radu_Lefter să dea mai multe amănunte. Eu mă cramponez de faptul că traducerea se face în context. Radu Lefter trebuie să înțeleagă că exemplul turcesc este pueril (din pdv. al utilității) Acum mă dau important și fac observația: Clarifică enunțul problemei (mai ales în ce privește utilitatea) și apoi apucă-te de program!

In primul rand va multumesc pentru timpul acordat problemei. Cred ca raspunsul lui alescx este cel mai aproape de o solutie.
In al doilea rand, mai multe detalii (si sper eu mai clare) despre ce vreau. Vreau ca atunci cand tin mouse-ul deasupra uni cuvant sa apara traducerea acelui cuvant si vreau o modalitate simpla sa introduc acea traducere eu personal pentru fiecare cuvant in parte. O data ce am introdus traducerea pentru un cuvant ea sa apara pentru orice instanta a acelui cuvant in site.

Pornind de la ideea lui alescx, rezolvarea cuprinde dictionar.js(ATENȚIE! salvat cu notepad UTF8) ce conține o secvență de tipul:

var d={'nume':'name','unirea':'union','Granitele':'traducerea cuvantului granite','Vecinătăţi':'traducerea cuvantului vecinătăți','cuv10':'trad10','cuv100':'trad100','copil':'child','curs':'course','s-a nascut':'is born'}

La fișierul HTML(oarecare, dar charset să fie UTF8) se adaugă la header:

script type=“text/javascript” src="dictionar.js

iar la sfârșitul fișierului HTML se pune:

for(var k in d)
{
    s=k;
    sRep=d[k];
    sss=ttt.innerHTML;
    var searchMask = s;
    var regExp = new RegExp(searchMask, "ig");
    var replaceMask = "<span title='"+sRep+"'>"+s+"</span>";
    var sss=sss.replace(regExp,replaceMask);
    ttt.innerHTML=sss;    
}

Atenție: Tot textul care interesează se include in tagul DIV cu id="ttt"!
Pentru simplificare am folosit title, dar se putea adăuga span cu mouseover, mouseout cu afișare text în fereastră flotantă.

Javascript clasic fără framework-uri!
GARANTEZ FUNCȚIONAREA!

Adaug faptul că se poate genera fișierul dicționar intr-un program c#(cum zice alescx backend) ce deschide toate fișierele site-ului și asistă utilizatorul în procesul de creare dicționar. Deasemenea include apelurile necesare in sursele HTML. Cine se oferă voluntar să-l scrie?

Nu am rezolvat situația când în dicționar apar: rar, rarefiat,florar,mărar.
Cred că o rezolvare ar fi ca atunci când se găsesc mai multe cuvinte ce conțin o radacină(aici rar) sa se înlocuiască întâi cuvintele mai lungi… O să revin!

Pe ghicite, aș zice că searchMask ar trebui să fie ceva de genul s + '(\s|\.)', astfel încât să faca match doar la pattern-ul inițial + spațiu & semne de punctuație.

Darrrr… nu cred că flagul i la regex este o idee chiar atât de bună; de exemplu, poți avea un nume propriu ce nu ar trebui tradus (e.g. sunt multe nume de flori).

Sunt curios cum s-ar comporta codul tău pe un text de peste 1-2000 cuvinte și eventual mai multe traduceri pentru fiecare cuvânt.

Eu cred că ar fi mai potrivit ca tot codul să fie generat de server, nu cu js. Js poate fi folosit (opțional!) pentru afișarea tooltip-ului.

Pentru iamntz: searchMask este corect. Se face o simplă înlocuire. Nu mă prea pricep la expresii regulate(vezi acel 1951 din nume). Dacă scot flagul i cum traduc cuvântul de la începutul unei propoziții?

Toate necazurile enunțate se rezolvă dacă se face un dicționar bun și dacă cuvintele exceptate de la traducere sunt puse de ex. între paranteze drepte ([[Cotoi]] este un politician versat.Am vazut pe strada X un cotoi. Cotoiul era negru.) - evident am grijă ca după replace cu regex să elimin [[ și ]]
Am uitat de sortarea dicționarului după lungimea cuvintelor, descrescător(ce elimină problema cu rar,mărar…)

Ideea cu codul pe server este foarte corectă. Foarte simplu se generează cod PHP. Nu știu dacă este locul aici pentru exemplificări PHP. Dacă e nevoie, revin cu mesaj.


Update: 23 august 2015 - 13:00


Problema cu codul pe server (asp,php etc) este că se repetă în neștire o secvență de adăugare taguri span pentru cuvintele din dicționar(care poate fi foarte mare). Moare serverul la datorie de pomană! Și în situația în care paginile respective nu sunt actualizate des este și mai absurd!
Mai corect este ca prelucrarea paginilor să fie făcută o singură dată după fiecare actualizare a unei pagini din site(local, apoi copiate pe server). Prelucrarea unei pagini actualizate presupune

  1. eventuala actualizare a fișierului dictionar.js general;
  2. eventuala actualizare a paginii modificând dicționarul local.
    Pagina actualizată conține deja codul javascript de mai sus. Insist cu varianta asta care reduce traficul client-server și execută o secvență minimă pe stația client(cu degrevarea serverului).
    Prelucrarea se poate face în orice limbaj.
    Scuze pentru exprimarea arhaică!

Dacă se optează pentru php pe server (varianta neoptimizată) atunci totul se simplifică prin crearea unui program php pe server care actualizează fișierul dicționar interactiv și astfel se respectă ultima cerință a lui Lefter.
Update: 26 august 2015 - 9:00


Vedeti un mic exemplu (html client) -O sa revin cu exemplul pe client/server:
var dictionary=[];
dictionary={'name':'nume','another':'alt','sentence':'propozitie','break':'pauza'};

var html=ttt.innerHTML;
    // ttt este id-ul unui div care contine numai textul ce intereseaza
    // se inlocuiesc toate tagurile HTML cu spatii (evident /i este inutil)
var html = html.replace(/(<([^>]+)>)/ig," ");
    // se inlocuieste cu spatiu orice caracter care nu e litera sau @
    // (adresele email raman intacte)
html = html.replace(/([^a-zA-Z@]+)/g, " ");
    // mai multe spatii se inlocuiesc cu unul singur
html = html.replace(/\s\s+/g, " ");
arrWords=html.split(' ');
nbrWords=arrWords.length;
html=ttt.innerHTML;
for(var i=1;i<nbrWords;i++){
	word=arrWords[i];
	wordLower=word.toLowerCase(); // foarte util
	if(wordLower in dictionary){
	html=html.replace(new RegExp(arrWords[i],"g"),
        "<span style='cursor:pointer' title='Traducere: ["+
         dictionary[wordLower]+"]'>"+word+"</span>");
	}
}
ttt.innerHTML=html;

Vă rog testați! Eu zic că merge!
1 Like

Traficul per se nu e o problemă foarte mare, din două motive:

  1. În cel mai rău caz, crește dimensiunea paginii de 3✕. Chiar și așa, exceptând situația în care este vorba de o carte afișată într-o singură pagină, sunt destul de slabe șansele ca dimensiunea să sară de 2-300kb.
  • Chiar și cu dimensiunea crescută, există gzip. Având în vedere că vorbim de cod care se repetă (span style... title...), dimensiunea crescută va fi, totuși, neglijabilă, rămânând doar dicționarul propriu-zis, care oricum ar trebui transferat într-un fel sau altul.

Deci rămâne doar de ales între: pun la treabă un singur sistem (serverul) sau fiecare client care îmi accesează site-ul (browserul)?

Având în vedere că pe server ai mult mai multe opțiuni de optimizare (e.g. caching), decizia nu cred că-i atât de grea :smile:

Nu neg asta, dar eu sunt curios cum merge în cazul unui text mai lung :smile:


Ca să-i răspund lui @Radu_Lefter: pentru WordPress nu cred să existe ceva, dar ai putea folosi un buton în tinymce care la apăsare îți cere o traducere și inserează în atributul title (sau data-* etc). Dar cred că-i o metodă suficient de complicată pentru a nu fi considerată o soluție…

Pentru fereastră flotantă am gasit codul(pe care l-am simplificat):
În header-ul HTML se adaugă secvența

    <!-- Copyright 2006,2007 Bontrager Connection, LLC
    // http://bontragerconnection.com/ and http://willmaster.com/
    // Version: July 28, 2007

    var d="floatWindow";
    var textCrt="";

    var cX = 0; var cY = 0; var rX = 0; var rY = 0;
    function UpdateCursorPosition(e){ cX = e.pageX; cY = e.pageY;}
    function UpdateCursorPositionDocAll(e){ cX = event.clientX; cY = event.clientY;}
    if(document.all) { document.onmousemove = UpdateCursorPositionDocAll; }
    else { document.onmousemove = UpdateCursorPosition; }
    function AssignPosition(d) {
    if(self.pageYOffset) {
        rX = self.pageXOffset;
        rY = self.pageYOffset;
        }
    else if(document.documentElement && document.documentElement.scrollTop) {
        rX = document.documentElement.scrollLeft;
        rY = document.documentElement.scrollTop;
        }
    else if(document.body) {
        rX = document.body.scrollLeft;
        rY = document.body.scrollTop;
        }
    if(document.all) {
        cX += rX; 
        cY += rY;
        }
    d.style.left = (cX+10) + "px";
    d.style.top = (cY+10) + "px";
    }
    function HC() {
    document.getElementById(d).style.display = "none";
    var dd = document.getElementById(d);
    dd.innerHTML="Traducere: []";
    }
    function SC(t) {
    var dd = document.getElementById(d);
    AssignPosition(dd);
    dd.style.display = "block";
    dd.innerHTML=dd.innerHTML.replace("[]",t);
    }

Se adaugă în body:

    <div 
       id="floatWindow" 
       style="display:none; 
          position:absolute; 
          border-style: solid; 
          background-color: white; 
          color:blue;
          padding: 5px;
          border-color:blue">
    Traducere: []
    </div>

În codul din comentariul precedent se înlocuiește secvența:

    html=html.replace(new RegExp(arrWords[i],"g"),
        "<span style='cursor:pointer' title='Traducere: ["+
        dictionary[wordLower]+"]'>"+word+"</span>");

cu secvența:

    aTag="<a onmouseover='SC(\""+dictionary[wordLower]+"\");return true;' onmouseout='HC();return true;'>"+word+"</a>";
    html=html.replace(new RegExp(arrWords[i],"g"),aTag);

Este cea mai bună variantă pentru javascript client!

Uite o variantă și mai bună, fără JS :smile:

Pune un demo al soluției tale pe codepen, dar pe mai multe cuvinte, cel puțin 1000 (poți folosi lorem ipsum, nu contează exact cuvintele), să vedem cum se comportă. Eu spun că se va vedea un impact cu atât mai mare cu cât sunt mai multe cuvinte.

Chiar ești dispus să pedepsești utilizatorii pentru a menaja serverul? :frowning:

eu tot pe server side as merge.

1 Like

O să postez la codepen.io!
Vin imediat cu soluția combinată server/client(PHP/javascript).
Pe server se iau toate fișierele de prelucrat și se adaugă dicționarul dar numai pentru cuvintele existente în fiecare fișier(direct constanta array - cât poate să fie de mare?)
Prelucrarea în javascript este accesibilă (se presupune că paginile au dimensiunea rezonabilă 100k-200k - nu discutăm de pagini de dimensiune aiurea - dacă aveți totuși un exemplu de astfel de pagină aiurea puneți link Internet - NU generată aleator)
Exemplul pe care o să-l pun va fi edificator!

Scuzați-mă dar am pus aici temporar codul (nefinisat) PHP. Nu ștergeți!

<?php
$s=file_get_contents('http://aiurea.eu/test.php');
$s=preg_replace('/(<([^>]+)>)/',' ',$s);
$s=preg_replace('/([^a-zA-Z@]+)/',' ',$s);
$s=preg_replace('/\s\s+/',' ',$s);
$v=explode(" ",$s);
$dict=file("http://aiurea.eu/dictionary.txt");
$v=array_map('strtolower',$v);
foreach ($dict as $el)
{
    $wordArray=explode(":",$el);
    $word=$wordArray[0];
    $word=str_replace("'","",$word);
    if(in_array(strtolower($word),$v))
        {echo "<br>".$el;};   
}
?>

Update 27.08.2015 - 8:30
@iamntz,@alescx: NU aveți dreptate cu viteza pe client (am testat 100k cu un dictionar de 50 cuvinte, execuția replace-urilor dureaza 1 sec. - acceptabil).
Am corectat scriptul client(vezi update din 26.08) - în loc de:

new RegExp(arrWords[i],"g")

se pune:

new RegExp("\\b"+word+"\\b","g")

astfel că se înlocuiesc numai cuvintele întregi și
am eliminat eroarea gravă :rage: care ducea la înlocuirea repetată a aceluiași cuvânt astfel
am folosit funcția de eliminare a duplicatelor în array - http://jsfiddle.net/ARnL3/ (în jQuery e mai simplu):

    var unique = function(origArr) {
        var newArr = [],
            origLen = origArr.length,
            found,
            x, y;
     
        for ( x = 0; x < origLen; x++ ) {
            found = undefined;
            for ( y = 0; y < newArr.length; y++ ) {
                if ( origArr[x] === newArr[y] ) { 
                  found = true;
                  break;
                }
            }
            if ( !found) newArr.push( origArr[x] );    
        }
       return newArr;
    }

și am apelat-o după ce array-ul arrWords a fost generat:

    arrWords = html.split(' ');
    arrWords = unique(arrWords);

Viteza a crescut enorm!

VEZI http://codepen.io/ab1951/pen/pjzbBz

Html-ul are peste 5000 cuvinte distincte și un dicționar de 201 termeni. Dimensiune fișier: 500KB.
Timpul de încarcare pagină și prelucrare este de aprox. 3 secunde.

Ctrl/q pe text arată/ascunde cuvintele care au traducere!!!