JavaScript translation - BTW or WTF?



  • Years ago I got a job writing a small HTML/JavaScript application, since then it has through added features grown to pretty big HTML/JavaScript application (150 kB in one file). The latest requested feature was translating the program. While I don't recall stuffing the program full of text, it turns out there is actually quite a lot of it, with no translation-friendly organisation. Not wanting to branch the application into different language version, or do any more work than necessary for that matter, I came up with an ingenious solution: Use JavaScript to edit the document when it's loaded in the users browser.



    First add some markings to identify plain text for translation:

    <span class="text0001">Plain text</span>

    Then write a script that packs all the text nicely into a JavaScript Object (export by copy pasting from Chromes JavaScript console):

    all=document.getElementsByTagName("*")

    dispout=""

    matchtext=/[0-9]{4}/

    strings=[ ]

    titles={}

    for(a=all.length-1;a;a--){

       b=matchtext.exec(all[a].className)

       if(b){

         index=parseInt(b,10)

         strings[index]=all[a].innerHTML

       }

       if(c=all[a].title){

         titles[c]=c

       }

       if(all[a].type=="button"){

         if(c=all[a].value){

           titles[c]=c

         }

       }

    }

    jsonstring=JSON.stringify({"strings":strings,"titles":titles}).replace(/\n/g,"").replace(/&lt;//g,"<\/").replace(/","/g,"",\n"")

    Then translate the lot and do the runtime magic:

    all=document.getElementsByTagName("*")

    dispout=""

    matchtext=/[0-9]{4}/

    for(a=all.length-1;a;a--){

       b=matchtext.exec(all[a].className)

       if(b){

         index=parseInt(b,10)

         all[a].innerHTML=clang.strings[index]

       }

       if(c=all[a].title){

         d=clang.titles[c]

         if(d){

           all[a].title=d

         }

       }

       if(all[a].type=="button"){

         if(c=all[a].value){

           d=clang.titles[c]

           if(d){

             all[a].value=d

           }

         }

       }

    }

    It works beautifully, I just ain't sure if I should be proud of it.



  •  Definitely a WTF, because now you need JavaScript enabled to view the page in any other language. (Did you mean FTW instead of BTW in the title?)



  • @immibis said:

     Definitely a WTF, because now you need JavaScript enabled to view the page in any other language. (Did you mean FTW instead of BTW in the title?)


    Well, it's a full blown JavaScript application, it doesn't do anything useful without JavaScript enabled anyway. Only problem is that it's kinda hard translating the "You need JavaScript enabled"-message in this manner. (BTW - Better than win - The logical opposite of "Worse than failure")



  •  "You need JavaScript enabled" should only be in one place so it'd be easy enough to translate on the server.

     FTW is WTF backwards, as well as being an opposite.



  • That looks like absolute hell to maintain. "text0001"?



  • @toth said:

    That looks like absolute hell to maintain. "text0001"?
    I left the original text in the HTML so it doesn't stand only as a dumb identifier, though it will be overwritten in all cases. That said, I haven't "maintained" this part of the application yet.



  • For a JavaScript app, it's not too bad of an idea. I'd do

    <span data-translationKey="text_0001">Hello world</span>
    

    instead of using a class, just in case you ever do want to use a class properly (you shouldn't really use the class attribute just for metadata). You can get the value of it using .getAttribute('data-translationKey').

    It'd be better to use translation keys that make sense, though:

    <span data-translationKey="HELLO_WORLD">Hello world!</span>
    

    Another alternative is to make a map of English to the other language, instead of using translation keys. This is how Gettext works, which is what projects like WordPress use. In that scenario, you might have something like

    <span data-translate="true">Hello world!</span>
    
    And then do something like this in your JS (sorry if the syntax is a bit wrong):
    var translatable;
    

    if (document.querySelectorAll)
    translatable = document.querySelectorAll('[data-translate=true]');
    else
    {
    translatable = [ ];
    var all = document.getElementsByTagName('
    ');
    for (var i = 0, var count = all.length; i < count; i++)
    {
    if (all[i].getAttribute('data-translate') == 'true')
    translatable.push(all[i]);
    }
    }

    // Loop through translatable and translate each one based on text content

    And your translation hash would be something like:

    var language = 
    {
    	// English => Other language
    	'Hello world!' => 'Todo: Translate "Hello World!" to another language',
    	// ...
    };
    


  • One can multiclass: class="text6438 romanstyle toosmallfortheaveragesighted" (and indeed I already use that feature).

    I used a translation method for the title and button texts, since that saved me the trouble of marking them. For the HTML text it's not so easy, since the readout of innerHTML is not consistent across browsers.


Log in to reply