Multilingual applications with JRapid
03/10/2008. Matias Bagini
JRapid handles multilingual applications through the stereotypes Language and LangValue.
Suppose we have an entity called article in which we want to store articles and we define that the article is compound by an author, a title and the text. Such an entity might look like this:
<entity name="Article" label="Article">
<property name="author" label="Author" />
<property name="title" label="Title" />
<property name="text" label="Text" type="richtext" />
</entity>
The Language Entity
In a multilingual application we would have to offer the title and text properties in more than one language. To accomplish this we have to add some new entites to our application.
The first step is to include an entity of stereotype Language to hold the information of the languages that our application will offer. To fulfill the requirements of the stereotype this entity must have a property named description to store the description of the language, and a property named abbr to store a short abbreviation of the name of the language (e.g we may use en for the english language).
<entity name="Language" stereotype="Language">
<property name="description" label="Description" unique="unique" display="primary" />
<property name="abbr" label="Abbr" />
</entity>
We can now add languages to our application with the generated form:

The LangValue entities
The next step is to create an entity to hold the various translations of a title. This entity should be of stereotype LangValue and to comply with the stereotype should include a property named 'lang' using the entity that we defined with the stereotype Language and a property named 'value'.
The 'lang' property indicates the language of the translation and the 'value' property holds the translated text.
The property named 'article' is not required by the stereotype but we need it here so that we can later embed this entity in the article entity.
<entity name="TitleLangValue" stereotype="LangValue">
<property name="article" entity="Article" />
<property name="lang" entity="Language" label="Lang" fixed="fixed" />
<property name="value" label="Value" />
</entity>
Now, it is clear that if we want to have translations of the title of the article the property that holds the title should have more than one value, so we make it a collection of our new 'TitleLangValue' entity:
<entity name="Article" label="Article">
<property name="author" label="Author" />
<property name="title" label="Title" entity="TitleLangValue" collection="set" embedded="inline" childproperty="article">
<foreach select="Language:findAll()" setproperty="lang" />
</property>
<property name="text" label="Text" type="richtext" />
</entity>
Now the title property may hold the translations of the title to all the offered languages. The 'foreach' tag inside the property makes an entry for each language defined in our 'Language' entity.
Notice that even if we named the entity with the translations 'TitleLangValue', this entity may be used to hold the translations of not only the article titles but also of any property of the same type (String in this case) as long as we add to the 'TitleLangValue' entity properties linking to the other entities, as we did with the property 'article'.
However, if we want to store translations of the text of the article we can't use the 'TitleLangValue' entity since the text is stored in another data type (richtext). To add the translations for the text we create the entity 'TextLangValue' as follows:
<entity name="TextLangValue" stereotype="LangValue" label="Text lang value">
<property name="article" entity="Article" />
<property name="lang" label="Language" entity="Language" fixed="fixed" />
<property name="value" label="Value" type="richtext" />
</entity>
The form to add articles now has fields for all the languages added to our application:
Complete Code
The code for the application supporting translations for the article title and text looks like this:
<entity name="Article" label="Article">
<property name="author" label="Author" />
<property name="title" label="Title" entity="TitleLangValue" collection="set" embedded="inline" childproperty="article">
<foreach select="Language:findAll()" setproperty="lang" />
</property>
<property name="text" label="Text" labelposition="fieldset" entity="TextLangValue" collection="set" embedded="inline" childproperty="article">
<foreach select="Language:findAll()" setproperty="lang" />
</property>
<property name="currentTitle" label="Title" hidden="hidden" expr="translate(this.title)" display="primary" />
</entity>
<entity name="Language" stereotype="Language">
<property name="description" label="Description" unique="unique" display="primary" />
<property name="abbr" label="Abbr" />
</entity>
<entity name="TextLangValue" stereotype="LangValue" label="Text lang value">
<property name="article" entity="Article" />
<property name="lang" label="Language" entity="Language" fixed="fixed" />
<property name="value" label="Value" type="richtext" />
</entity>
<entity name="TitleLangValue" stereotype="LangValue">
<property name="article" entity="Article" />
<property name="lang" entity="Language" label="Lang" fixed="fixed" />
<property name="value" label="Value" />
</entity>
We have added the 'currentTitle' property to the entity to hold the text of the title in the language that is being used at the moment. The translate function used in the expression does exactly that: set the property with the value of the title that corresponds to the language that being used in the current session.
Conclusion
Adding multilingual support to our JRapid applications is done smoothly using the provided 'Language' and 'LangValue' stereotypes. It is important to decide early in the development if the application will support more than one language otherwise adding the languages will result in substantial rewriting of code.