views:

376

answers:

6

I have an application that needs to support a multilingual interface, five languages to be exact. For the main part of the interface the standard ResourceBundle approach can be used to handle this.

However, the database contains numerous tables whose elements contain human readable names, descriptions, abstracts etc. It needs to be possible to enter each of these in all five languages.

While I suppose I could simply have fields on each table like

NameLang1
NameLang2
...

I feel that that leads to a significant amount of largely identical code when writing the beans the represent each table.

From a purely object oriented point of view the solution is however simple. Each class simply has a Text object that contains the relevant text in each of the languages. This is further helpful in that only one of the language is mandated, the others have fallback rules (e.g. if language 4 is missing return language 2 which fall back to language 1 which is mandatory).

Unfortunately, mapping this back to a relational database, means that I wind up with a single table that some 10-12 other tables FK to (some tables have more than one FK to it in fact).

This approach seems to work and I've been able to map the data to POJOs with Hibernate. About the only thing you cant do is map from a Text object to its parent (since you have no way of knowing which table you should link to), but then there is hardly any need to do that.

So, overall this seems to work but it just feels wrong to have multiple tables reference one table like this. Anyone got a better idea?

If it matters I'm using MySQL...

+2  A: 

I had to do that once... multilingual text for some tables... I don't know if I found the best solution but what I did was have the table with the language-agnostic info and then a child table with all the multilingual fields. At least one record was required in the child table, for the default language; more languages could be added later.

On Hibernate you can map the info from the child tables as a Map, and get the info for the language you want, implementing the fallback on your POJO like you said. You can have different getters for the multilingual fields, that internally call the fallback method to get the appropiate child object for the needed language and then just return the required field.

This approach uses more table (one extra table for every table that needs multilingual info) but the performance is much better, as well as the maintenance I think...

Chochos
This sounds like the best compromise but I'm still not 100% happy with it. Seems you wind up with a good deal of extra code to manage the additional multilang tables.
Kris
A: 

The standard translation approach as used, for example, in gettext is to use a single string to describe the concept and make a call to a translate method which translates to the destination language.

This way you only need to store in the database a single string (the canonical representation) and then make a call in your application to the translate method to get the translated string. No FKs and total flexibility at the cost of a little of runtime performance (and maybe a bit more of maintenance trouble, but with some thought there's no need to make maintenance a problem in this scenario).

Vinko Vrsalovic
These aren't just 'concepts', they include more detailed textual descriptions of the items that the table entries signify.
Kris
No problem, it's still a concept, if a more complex or long one, like DescriptionOfCombobox2 corresponding to "Select the name of the user for the credit" or a lot more of text.
Vinko Vrsalovic
A: 

The approach I've seen in an application with a similar problem is that we use a "text id" column to store a reference, and we have a single table with all the translations. This provides some flexibility also in reusing the same keys to reduce the amount of required translations, which is an expensive part of the project.

It also provides a good separation between the data, and the translations which in my opinion is more of an UI thing.

If it is the case that the strings you require are not that many after all, then you can just load them all in memory once and use some method to provide translations by checking a data structure in memory.

With this approach, your beans won't have getters for each language, but you would use some other translator object:

 MyTranslator.translate(myBean.getNameTextId());
Mario Ortegón
A: 

Depending on your requirements, it may be best to have a separate label table for each table which needs to be multilingual. e.g.: you have a XYZ table with a xyz_id column, and a XYZ_Label table with a xyz_id, language_code, label, other_label, etc

The advantage of this, over having a single huge labels table, is that you can do unique constraints on the XYZ_labels table (e.g.: The english name for XYZ must be unique), and you can do indexed lookups much more efficiently, since the index will only be covering a single table at a time (e.g.: if you need to look up XYZ entities by english name) .

Chi
A: 

Can someone tag this with "i18n" please?

rmp
A: 

What about this: http://rob.purplerockscissors.com/2009/07/24/internationalizing-websites/ ...that is what user "Chochos" says in response #2

Olagato