Text Translator
Contents
Overview
The App Text Translator delegate allows for a function to intercept text messages before they are displayed. This delegate function can return an alternative message. The returned message can be in a different language, or just a message that is easier for your users to understand. The returned message will be displayed instead of the default text.
This is used to custom translate messages, captions and other text in Web and Mobile Apps.
So, for example, instead of your users seeing this when a record is successfully updated:
They could see this:
and similarly in the Web Client, instead of this:
this:
or this:
or this:
The message returned is entirely dependent on the code in the Text Translator delegate procedure.
Text Translator Delegate
The Text Translator delegate is created at App level. Click Settings in the Modebar.
For these examples, I have created a Library Lianja/VFP script (transtext.prg) to handle the translation, so my delegate just calls the script, passing it the default message ('arg' passed to the delegate procedure) and any additional parameters, here 'it'.
//////////////////////////////////////////////////////////////// // Event delegate for 'texttranslator' event function z_transtextjs_texttranslator(arg) { return Lianja.evaluate("transtext('"+arg+"','it')"); };
The equivalent Lianja/VFP delegate procedure for desktop only Apps would be:
//////////////////////////////////////////////////////////////// // Event delegate for 'texttranslator' event proc z_transtext_texttranslator(arg) return transtext(arg,'it') endproc
And here is my transtext.prg in the Library:
// transtext.prg parameter cText2Trans, cLang if pcount() < 2 cLang = "fr" endif //if isserver() // // These are message titles in the web/mobile client // // you may want to handle these differently // if inlist(cText2Trans,"Error","Information","Message","Success") // return cText2Trans // endif //endif do case case len(cLang) = 2 return keylookup("translations!messages_&cLang","original",alltrim(cText2Trans),alltrim(modified),cText2Trans) case cLang = "annoying" return cText2Trans + "...just sayin'") otherwise return cText2Trans endcase // end of transtext.prg
The main case statement:
return keylookup("translations!messages_&cLang","original",alltrim(cText2Trans),alltrim(modified),cText2Trans)
uses the KEYLOOKUP() function (for an SQL equivalent, use SQLLOOKUP()) to look up the default message in the index of a table in the translations database that I have created. Since the cLang parameter received the value 'it', the table is messages_it, which I have created with the following values for sample messages from the desktop and web clients:
Record # id original modified 1 0000000001 Success Riuscito 2 0000000002 Information Informazione 3 0000000003 Error Errore 4 0000000004 Message Messaggio 5 0000000005 Record was updated. I dati sono stati aggiornati. 6 0000000006 Record was added. I dati sono stati inseriti. 7 0000000007 Record was updated I dati sono stati aggiornati 8 0000000008 Record was created I dati sono stati inseriti
The KEYLOOKUP() function uses an index on the table, so I have also created an index tag (create it in the Command Window):
index on original tag original
I've created a similar table, messages_fr and its original index tag to be used when the cLang is 'fr' as shown in the screenshot earlier.
If the message is not found in the table, the KEYLOOKUP() function just returns the original message passed (cText2Trans).

The returned message can include HTML formatting with {...} macros.
Web Client System Messages
Web Client System Messages list.
Dynamic Language Translation
Dynamic Language Translation was introduced in Lianja v5.5. This extends text translation in web/mobile Apps to cover text in the UI: captions, tooltips, menus etc. Dynamic Language Translation can be script-based using the Text Translator Delegate or with Google translate.