ramblings on PHP, SQL, the web, politics, ultimate frisbee and what else is on in my life
back

Inline translation for AJAX applications

On my last project I was asked to make life a bit easier for translators, by allowing them to get immediate visual feedback from changes they make. Now I have done something like this before by simply allowing editors to authenticate which then gives them an "enable edit mode" button. When clicked, the current page is reloaded with "edit" buttons next to anything that should be editable. Clicking on the edit button would bring up a popup window. Submitting the form in the popup with the modified content would trigger reloading the opening page and viola, the modified content is visible. Simple solution, but obviously not really useful for AJAX applications, mainly because the reloading of the page would not preserve the state of the interface properly and I also wanted to tweak some other aspects.

So the solution I came up with is quite simple. Essentially all translations are handled by embedding calls to the __() function inside the templates. The first parameter is the default text to display if no translation is found. The second parameter controls if this variable should be inline editable. Unfortunately in my current solutions some text my not be editable. For example an items inside a select option list. I have not really pondered about how to deal with that one yet.

Now if the user is authenticated as an editor, he automatically gets a nice javascript overlay which can be moved around, so that it does not break the layout of the page. Also all text that is not yet translated to the current language is displayed in yellow (or some other color you are not likely to use). When clicking on the "enable edit mode" button. All text that can be edited is displayed with a green background. This is implemented by rewriting the class that is used to surround all translatable text on the fly with javascript.

More importantly, the text also becomes a link, that suppressed any click events from cascading (actually this one does not work reliably yet, but with returning false I at least got it to not follow <a href>, I need to investigate that one). The active link is responsible for opening a popup with the given text in a textarea. Clicking on the link also turns the background color of the given text to blue so that it is easy to remember what you are currently editing. Underneath the popup box is a language selector. Clicking on a language loads the translation for the same string from the database via AJAX underneath the textarea.

Now the real trick comes into play when you click submit to update the given text. When clicking on the text in the parent window a reference to the DOM node is stored. This reference is used to update the DOM node with the new text just before the form is actually submitted. This way the translator can immediately see his change. Simultaneously the database is updated with the new translation. In the future I want to get rid of the reference and simply traverse the entire DOM for all instances of the given string, since the same string could be used multiple times in a page.

When I got all of this working the next requirement came in. Some of the text in the interface should use non standard fonts according to the CI. Now I needed to adapt my solution to also work with on the fly transparent images. I still need to get the png behavior hack for MSIE6 to work right, so for now my solution is that I have a new helper function called trans_image_tag() which accepts a text string just like the __() function as the first parameter and the second parameter is either an individual configuration of font type, font size color etc. or a class which maps the a font definition (I do not reverse engineer the CSS classes .. now that would be über-cool).

If GD2 is installed the system an image tag is generated to a script that can generate transparent png's (or gif's if the user is browsing with MSIE6 or lower) for the requested configuration. If GD2 is not available the text is just outputted as plain text. The generated image is cached, as on the next request the trans_image_tag() function will realize that the file is cached and instead of pointing to the script that generates images on the fly, it just points the user to the URL of the cached image.

Anyways, the original topic was inline translation and obviously I wanted to integrate this solution with my plain text solution. Actually its quite simple what needs to be done. I simply expanded my plain text solution to simply rewrite the image source attribute to point to my image generation script just before the submit. Badadum, inline translation is now also possible for text in generated images.

So far things are working fairly well. Obviously there are a few things to tweak. For example I want to add a button for translators to update the current view without submitting. Like I mentioned before, I also need to prevent clicks from cascading entirely and fix the hacks for png support in MSIE6. Furthermore I want to traverse the DOM tree to update all instances of the given text in the current view. But overall things are working quite nice and the client is happy. I am sure someone else has done something like this already, but I have not .. so :)

As some people might have guessed from the function names I hacked this stuff into the sfI18N class of symfony. Unfortunately symfony does not allow easy extending the internal I18N classes and the implementation is still a bit hacky. But once I have confirmed with my client that releasing source is ok, I will try my best to make the code available in some form or another. If there are some javascript experts around that can help me on some of the above mentioned issues .. feel free to leave a comment :)

Comments



Re: Inline translation for AJAX applications

What to hell is "über-cool" ? ;-)

Re: Inline translation for AJAX applications

For the 'inline editing' part, have a look at a little script called 'eeip' we created a while ago. You can also use it to edit dropdowns in place, as long as you provide an edit widget.

http://www.epointment.com/software/eeip

Re: Inline translation for AJAX applications

For the a href="" following you might want to have a look at YAHOO.util.Event.preveventDefault()

Basically you setup a listener on the the href and use preventDefault so it is not followed.

hth