Simple multi-lingual forms using Domino
Your customer wants a multi-lingual Domino web application that is able to switch languages in real time. Furthermore, it has to be possible to add and edit languages without much hassle. Besides that, your customer doesn’t want to invest in additional tools, so you can only use the Domino Designer.
The end result of the application has to look like the forms below. First, the form in English:
And the form in Dutch:
Solution:
As the customer doesn’t want to invest in any additional tools (neither licenses nor time to learn a free tool) you will have to stick to Domino Designer. Fortunately for us this is not going to be as problematic as you might first think.
One solution would be to create a form or a view for every language. But imagine the number of design elements in your database if you did this! Furthermore, you will have to do some fancy trickery to make sure the system uses the correct form for the specific language.
Another, much simpler (at least, that’s what we think) solution would be to make one form, and put all the languages on that form. Not using hide-whens, but using a more centralised and structured approach.
Let us try to explain the concept of our solution step by step:
- Create a multi-value, computed-for-display field on every form for each language. Call this field TransXX, where XX is a language code, e.g. TransNL or TransEN for Netherland and England respectively. These fields are going to hold all text elements you want translated.
- Create a multi-value, computed-for-display field on each form called TransID: this field is going to hold an identifier for every text element specified in 1.
- Note that the position (list index) of an ID in the TransID field has to be same as the translated text in the TransXX fields, since we’ll be using this position later.
Let’s try to explain this somewhat further. Take the following form as an example
In the form above, several textual elements can be recognised. In the table below I have assigned them an ID and also translated them into Dutch
ID | English | Dutch |
FillIn | Please fill in the following fields | Vul de volgende velden in a.u.b. |
Name | Name | Naam |
Address | Address | Adres |
Telephone | Telephone number | Telefoonnummer |
Now I create the fields as described above, being TransID, TransEN and TransNL. These fields are all “Computed for Display”, multi-value fields. The values I put in these fields are listed below.
TransID
“FillIn”,
”Name”,
”Telephone”
TransEN
“Please fill in the following fields”,
”Name”,
”Telephone number”
TransNL
“Vul de volgende velden in a.u.b.”,
”Naam”,
”Adres”,
”Telefoonnummer”
Glueing it all together:
This whole method is glued together with what we call the “TransApplied” field. The TransApplied field is filled in when the form is opened by reading a) the the current language and based on that, b) the translated text elements in one of the TransXX fields.
When you need a text label on your form/document/view, you do a lookup in the TransID field, to find the label with a specific ID and retrieve its position in the list (index). After that you can retrieve the translated text from the TransApplied field at the looked up index.
There are different options to read the language that must be displayed. To name a few:
- Using a URL parameter (http://
/database.nsf?open&lan=NL”; - Retrieving it from the “HTTP_Language” CGI Variable or;
- By setting a cookie somewhere in your application.
The language field in our sample database is filled with an @Formula (notice this is R6 only, although it can be done in R5 as well):
URLLanguage := @UrlQueryString("lan");
BrowserLanguage := @Left(@GetHTTPHeader("Accept-Language");2);
DefaultLanguage := "EN";
@If(
URLLanguage != ""; URLLanguage;
BrowserLanguage !=""; BrowserLanguage;
DefaultLanguage
);
What this formula does is read the “lan” parameter from the URL. If it cannot find it, it will get the Accept-Language header line from the HTTP Header. If it cannot find that, it will revert to the default language code: EN. Again, like the fields above, the Language field is computed-for-display.
So now we have figured out the language to use, it’s time to fill the TransApplied field, which will contain the translation which is going to be used on the form. The TransApplied field has the following formula as its value:
In Domino 6:
@GetField("Trans"+Language)
In Domino 5:
@If(
Language=”NL”; TransNL;
Language=”EN”; TransEN;
TransEN
);
Now we have several fields on form already, but still no actual text labels. You will have to modify your form in such a way that everywhere you want a text label, you create a <Computed Value> (or a computed-for-display field).
The computed value contains this formula:
In Domino 6:
ID := "Fillin";
ListLocation := @Member(ID; TransID);
TransApplied[ ListLocation ]
In Domino 5, change the last line to: @GetMembers(TransApplied; ListLocation)
Note: @GetMembers is an undocumented and pretty handy @formula, you can achieve the same result using @Subset.
Let us describe what goes on when you open a form/document/view:
- You open the form in a webbrowser;
- The ‘form’ checks if you have specified a lan parameter;
- If so it will use that as a language setting, if not it will check if your browser specified an accept-language header. If not it will revert to a default language;
- The form will work out the corresponding translations from the TransXX field and will put those fields in the TransApplied field;
- All the labels will show up using the correct language.
Following is a screen shot of a ‘translated’ form in designer mode:
What about views? It can be done using this method: we did that to. Just a small howto:
- Make sure that the TransApplied and TransID fields are available as hidden HTML fields;
- Create your own javascript function which returns and writes (‘document.write’) the correct translation given a certain id;
- Instead of writing a column header in a view do a call to this javascript function which will then write out the correct translation.
Furthermore, radio button field values can also be done. There’s an example in the database to show you how.
Conclusion:
We fully understand that you might be a bit confused reading all this stuff about TransID, TransEN, TransNL and TransApplied fields. That’s why we’ve included a database that you can download and check out to see how it works in a live situation. Once you understand how it works it’s really simple to make multi-language domino applications.
Advantages:
- It’s fast! There are no dblookups to any other data in the database;
- It’s highly structured/standardisd, allowing other developers to easily read your code;
- All translations are stored centrally in the design. Adding a new language and chaging current ones is relatively easy, since you know where to look.
Disadvantages:
- Reading the form in designer mode is a bit more difficult;
- Translations are embedded in the design of the application. If you need a front-end to add/change languages, you will have to modifiy the described method.
Editor's Note:
Thanks to Erwin van Hunen and Mark Leusink for this artlce. It's not a problem I've come across before and so I would not have though of writing it myself. Lucky for you lot that they did.
I've added an online version here for you to play with. Enjoy.
Jake, codestore.net webmaster.
Keywords
What about keywords? How would you handle multilingual keywords?
Living in an officially bilingual environment (well, in Quebec, but the rest of Canada is all English), I can relate to this. True that the possibility to switch languages live is needed, and I don't think it's acheivable any other way (believe me, I tried), especially on the web.
Domino Global Workbench is just a pain to maintain (the older version was a bit easier to use when adding fields and things that needed to be tagged - or I just need a really good DGW training!!!) so I tend to avoid it.
Good work guys. I can't wait for the follow up article on managing multilingual keywords and maybe one on DGW!!?!?!?
Reply
Re: Keywords
Check out the example included. There is an example on how to handle keywords (in this case a radio button/keyword field)
Reply
Brilliant!
Reply
An alternative approach
Erwin / Mark,
As an alertnative you could use keyword documents which store a list of string literals against there translated values keyed on language, rather than storing the data in design elements.
Granted there is 1 lookup(based on the users desired language) but it means a standard user can maintain the translations rather than having to go into the designer. As a bonus the translation data could be used in any agents which need to output text.
Reply
Re: An alternative approach
But then you get in to a mess when you start mixing design with data. What if they *user* accidentally deletes one of the values? The design is broken!
Think of a mono-lingual form. You wouldn't normally think of making the labels a user-editable setting would you. So why make it editable just because there's more than one language? Field lables are part of the design and so belong in the design of the form. IMHO ;o)
Of course, I see the benefit of having it editable, i just think it's a recipe for disaster...
Jake
Reply
Show the rest of this thread
Re: An alternative approach
That could be an option. But what happens if you, say, have an application developed for a user, and you provide the user with a new version by sending them a template so they can do a design refresh?
Right now there is no support for documents in templates, i.e. refreshing a 'document' by doing a design refresh. So this would mean you have to distribute several documents too, with updated translations.
In the form based solution we presented this is handled out of the box.
Reply
Show the rest of this thread
Re: An alternative approach
I agree it could be handy to allow end users to change the translations. I've extended this solution for another customer who required the option to add new languages to their (intranet/internet) site without designer interference.
Besides the drawbacks mentioned (you could force the user to enter the correct translations and/or do a conversion when implementing new versions), there's of course the 64k limit. The method described was developed for a large application with lots of translations. If we wanted to use lookups, we'd have to split them, which would make this method much more complicated to implement.
Reply
Show the rest of this thread
using div's instead of computed text
Nice to read an article from some Dutch authors!
I often run into the same problems with bilingual sites. Not being fond of server calculations, I use CSS to display and hide divs and spans for English or Dutch field labels or text.
1) two style sheets, one names nl.css with the following code: .dEN { display: none; }
.dNL { display:''; }
the other named en.css with the oposite code:
.dNL { display: none; }
.dEN { display:''; }
2) HTML with the following code e.g. in front of the name field
(span class="dNL")Naam(/span)(span class="dEN")Name(/span)
3) activate one or the other style sheet by either: - computed text that intercepts the &lan= parameter from the url - javascript that reads the cookie (doesn't work when users disable cookies) - javascripts that sets the style sheet based on the parent frame the html is placed in
E.g. http://ivetesangalo.com is a prototype of a bilingual site. Based on the ip number where you are coming from, it either redirects you to the PT page or the EN page. The EN page contains a frameset, a javascripts selects the isfsEN.css stylesheet that goes with it.
Reply
Re: using div's instead of computed text
Doesnt this mean that all translations are downloaded to the browser (though only one visible), whereas computed text only displays the relevant data.
Reply
Show the rest of this thread
Re: using div's instead of computed text - OFF
sorry for the off-topic guys, but i've noticed that Ivete Sangalo's web site is running in domino. How wonderfull!!! Laurens, are you working with some Brazilian guys on this project?
Again, sorry about the off.
Valdecir Carvalho
Reply
Invalid NSF version
I downloaded the file. Unfortunately, I encountered the invalid NSF version. From what I know, I can't read this version if I'm using R5. What about a sample that's compatible the R5 users?
I know that most people like new things, new versions of software... However, they may not apply to companies that have budget planning and they won't be upgrading to the latest version as fast the employees would like.
Reply
Re: Invalid NSF version
Charlotte. I agree and wish it were easier for me to supply versions that worked on both versions.
This case is difference in that they have come up with what is primarliry an R6 solution that uses a lot of R6's new features. If you were to open it in R5 you would see a lot of strange things.
To those people still stuck with R5 I suggest that, to see R6 version DBs, you download the R6 client and install it alongside R5. It can be done. Then you have the chance to see not only that database but also to get acquainted with Domino 6 and ready yourself for the transition.
Jake
Reply
Re: Invalid NSF version
Charlotte,
The solution was build for a R5 application. Although we've used some R6 features in the sample, the solution can perfectly be used in a R5 app.
If you (or others) are still interested in a R5 version, let me know and I'll convert the sample back to R5.
Reply
Plagiarism!
Seen this solution before!
Thanx for mentioning the real architects (Peter de Graaf & Pascal Scheurink) ;-)
Reply
Re: Plagiarism!
People tend to come up with the same solutions as long as the goal is the same and the road to the goal narrow enough. I did something similar with my survey database a while ago, and I imagine I am not the only one with likewise approaches.
The positive thing is that it has been put in an article and made known to the public, because I prefer this to the global workbench thing.
All the best, << Herbert http://van.vliet.net
Reply
Re: Plagiarism!
Hi Pascal!
It could have been called plagiarism if Mark and I would have claimed to be the one who came up with the idea. I'm just merely describing something you introduced to me in concept.
I stand corrected that I should have mentioned your and Peter's name. Let's have a beer soon, I'll buy you one and maybe even two ;-)!
Reply
Show the rest of this thread
What about field multilingual
Hi, This is wonderfull. You have really shown a new approach for building multilingual web applications.
The only gap that I found in this article which I want to highlight for further discussion is, the article assumes the SCRIPT that the user will be using is English. How do we handle the situation where by the user may use a script other than english e.g. Chinese?
How do we customize the field input script? Any suggestion?
Regards Tamajit
Reply
Re: What about field multilingual
Hi Tamajit,
I didn't understand your question completely. If you mean JavaScript and want a suggestion for field validation I can give you two alternatives:
- use HTML hidden fields (that contain the translated texts) and show those to the user
or
- create javascript page for every language containing the correct messages. Load the correct page based on the current language setting ("lan_en.js", "lan_nl.js")
Cheers
Reply
Show the rest of this thread
How would you apply this to a Checkbox?
Can you change the Choices of a checkbox using this method ? I'm trying to set the Choices value using the same formula than for the <Computed Value> fields, but I get an "Array out of bounds" error. Any clues ?
Reply
Re: How would you apply this to a Checkbox?
It seems in Notes 7.0.2, TransApplied field is not available in the Choices context. The radio button example in your sample DB does not work (shows "Array index out of bounds").
Reply
Show the rest of this thread
Content in a view
I am working on an app that needs this exact funtionality. However, I'm wondering how you can display column content in a specified language. My example is all the documents have a status value that we display in the views. Ideally, I would want the status to be translated to the selected language. FYI, these are huge views, so I would hate to have to use javascript to alter the displayed content....because I think some of the users would see it as it was updating.
Any suggestions?
Reply
The solutions is very good.
The other solution is this short example:
<span id= "id_name">id_name</span>
...
<script type="text/javascript" language="javascript">
FIELD with @DbLookUp
</script>
But i need to do without hard code and without @dblookup too.
Do you know how?
Best Regards,
Rodrigo
Reply