<p>A friend of mine is now building a web application with J2EE and Struts, and it's going to be prepared to display pages in several languages.</p>

<p>I was told that the best way to support a multi-language site is to use a properties file where you store all the strings of your pages, something like:</p>

<pre><code>welcome.english = "Welcome!"
welcome.spanish = "¡Bienvenido!"
...
</code></pre>

<p>This solution is ok, but what happens if your site displays news or something like that (a blog)? I mean, content that is not static, that is updated often... The people that keep the site have to write every new entry in each supported language, and store each version of the entry in the database. The application loads only the entries in the user's chosen language.</p>

<p>How do you design the database to support this kind of implementation?</p>

<p>Thanks.</p>

[{'answer_id': 39587, 'author': 'Espo', 'author_id': 2257, 'author_profile': 'https://Stackoverflow.com/users/2257', 'pm_score': 4, 'selected': True, 'text': '<p>They way I have designed the database before is to have an News-table containing basic info like NewsID (int), NewsPubDate (datetime), NewsAuthor (varchar/int) and then have a linked table NewsText that has these columns: NewsID(int), NewsText(text), NewsLanguageID(int). And at last you have a Language-table that has LanguageID(int) and LanguageName(varchar).</p>\n\n<p>Then, when you want to show your users the news-page you do:</p>\n\n<pre><code>SELECT NewsText FROM News INNER JOIN NewsText ON News.NewsID = NewsText.NewsID\nWHERE NewsText.NewsLanguageID = &lt;&lt;Session["UserLanguageID"]&gt;&gt;\n</code></pre>\n\n<p>That Session-bit is a local variable where you store the users language when they log in or enters the site for the first time.</p>\n'}, {'answer_id': 41379, 'author': 'reefnet_alex', 'author_id': 2745, 'author_profile': 'https://Stackoverflow.com/users/2745', 'pm_score': 4, 'selected': False, 'text': '<p>Warning: I\'m not a java hacker, so YMMV but...</p>\n\n<p>The problem with using a list of "properties" is that you need a lot of discipline. Every time you add a string that should be output to the user you will need to open your properties file, look to see if that string (or something roughly equivalent to it) is already in the file, and then go and add the new property if it isn\'t. On top of this, you\'d have to hope the properties file was fairly human readable / editable if you wanted to give it to an external translation team to deal with. </p>\n\n<p>The database based approach is useful for all your database based content. Ideally you want to make it easy to tie pieces of content together with their translations. It only really falls down for all the places you may want to output something that <em>isn\'t</em> out of a database (error messages etc.). </p>\n\n<p>One fairly old technology which we find still works really well, is to use gettext. Gettext or some variant seems to be available for most languages and platforms. The basic premise is that you wrap your output in a special function call like so: </p>\n\n<pre><code>echo _("Please do not press this button again");\n</code></pre>\n\n<p>Then running the gettext tools over your source code will extract all the instances wrapped like that into a "po" file. This will contain entries such as:</p>\n\n<pre><code>#: myfolder/my.source:239\nmsgid "Please do not press this button again"\nmsgstr ""\n</code></pre>\n\n<p>And you can add your translation to the appropriate place:</p>\n\n<pre><code>#: myfolder/my.source:239\nmsgid "Please do not press this button again"\nmsgstr "s’il vous plaît ne pas appuyer sur le bouton ci-dessous à nouveau"\n</code></pre>\n\n<p>Subsequent runs of the gettext tools simply update your po files. You don\'t even need to extract the po file from your source. If you know you <em>may</em> want to translate your site down the line, then you can just use the format shown above (the underscored function) with all your output. If you don\'t provide a po file it will just return whatever you put in the quotes. gettext is designed to work with locales so the users locale is used to retrieve the appropriate po file. This makes it really easy to add new translations.</p>\n\n<h3>Gettext Pros</h3>\n\n<ul>\n<li>Doesn\'t get in your way while coding</li>\n<li>Very easy to add translations</li>\n<li>PO files can be compiled down for speed</li>\n<li>There are libraries available for most languages / platforms</li>\n<li>There are good cross platform tools for dealing with translations. It is actually possible to get your translation team set up with a tool such as <a href="http://www.poedit.net/" rel="noreferrer">poEdit</a> to make it very easy for them to manage translation projects</li>\n</ul>\n\n<h3>Gettext Cons</h3>\n\n<ul>\n<li>Solves your site "furniture" needs, but you would usually still want a database based approach for your database driven content</li>\n</ul>\n\n<p>For more info on gettext see <a href="http://en.wikipedia.org/wiki/Gettext" rel="noreferrer">this wikipedia page</a></p>\n'}, {'answer_id': 42709, 'author': 'reefnet_alex', 'author_id': 2745, 'author_profile': 'https://Stackoverflow.com/users/2745', 'pm_score': 1, 'selected': False, 'text': '<p>@Auron</p>\n\n<p>thats what we apply it to. Our apps are all PHP, but gettext has a long heritage. </p>\n\n<p>Looks like there is a <a href="http://www.gnu.org/software/autoconf/manual/gettext/Java.html" rel="nofollow noreferrer">good Java implementation</a></p>\n'}, {'answer_id': 50669, 'author': 'ScArcher2', 'author_id': 1310, 'author_profile': 'https://Stackoverflow.com/users/1310', 'pm_score': 2, 'selected': False, 'text': '<p>Java web applications support internationalization using the java standard tag library.</p>\n\n<p>You\'ve really got 2 problems. Static content and dynamic content.</p>\n\n<p>for static content you can use <a href="http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSTL6.html" rel="nofollow noreferrer">jstl</a>. It uses java <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html" rel="nofollow noreferrer">ResourceBundle</a>s to accomplish this. I managed to get a <a href="https://stackoverflow.com/questions/19295/database-backed-i18n-for-java-web-app">Databased backed bundle</a> working with the help of this site.</p>\n\n<p>The second problem is dynamic content.\nTo solve this problem you\'ll need to store the data so that you can retrieve different translations based on the user\'s Locale. (Locale includes Country and Language).</p>\n\n<p>It\'s not trivial, but it is something you can do with a little planning up front.</p>\n'}, {'answer_id': 68873, 'author': 'Andrew Swan', 'author_id': 10433, 'author_profile': 'https://Stackoverflow.com/users/10433', 'pm_score': 1, 'selected': False, 'text': '<p>Tag libraries are fine if you\'re using JSP, but you can also achieve I18N using a template-based technology such as <a href="http://freemarker.sourceforge.net/" rel="nofollow noreferrer" title="FreeMarker">FreeMarker</a>.</p>\n'}]
['https://Stackoverflow.com/questions/39562', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/1679/']