001 package hirondelle.web4j.ui.translate; 002 003 import hirondelle.web4j.request.LocaleSource; 004 005 import java.util.Locale; 006 007 /** 008 Translate base text into a localized form. 009 010 <P>See {@link hirondelle.web4j.BuildImpl} for important information on how this item is configured. 011 {@link hirondelle.web4j.BuildImpl#forTranslator()} returns the configured implementation of this interface. 012 013 <P>Here, "<b>base text</b>" refers to either : 014 <ul> 015 <li>a snippet of user-presentable text in the language being used to build the application 016 <li>a "coder key", such as <tt>"image.title"</tt> or <tt>"button.label"</tt>. 017 Coder keys are never presented to the end user, and serve as an alias or shorthand 018 for something else. They are intended for the exclusive use of the programmer, and may 019 be thought of as being in a special "language" understood only by the programmer. 020 </ul> 021 022 <P><span class="highlight">In code, it is likely best to use user-presentable text 023 instead of coder keys, whenever possible - since lookups are never needed, it makes 024 code clearer at the point of call.</span> 025 026 <P>Please see the package <a href="package-summary.html">overview</a> for an interesting way of 027 evolving the implementation of this interface during development, allowing applications to assist in their 028 own translation. 029 030 <P>One might validly object to a framework which requires an implementation of this 031 interface even for single-language applications. However, arguments in favor of 032 such a style include : 033 <ul> 034 <li>providing a do-nothing implementation for a single-language application is trivial. 035 <li>changing from a single language to multiple languages is a common requirement for 036 web applications. The presence of this implementation makes it clear to the maintainer 037 where such changes are made, if they become necessary. 038 <li>some programmers might prefer to name items as <tt>'emailAddr'</tt> instead of 039 <tt>'Email Address'</tt>, for instance. In this case, a {@link Translator} can also 040 be used, even in a single-language application, to translate from such 'coder keys' 041 to user-presentable text. 042 </ul> 043 044 <P>The recommended style is to implement this interface with a database, and to 045 <a href="http://www.javapractices.com/Topic208.cjp">avoid <tt>ResourceBundle</tt></a>. 046 047 <P><b>Guidance For Implementing With A Database</b><br> 048 Example of a web application with the following particular requirements 049 (see the example application for further illustration): 050 <ul> 051 <li>English is the base development language, used by the programmers and development team 052 <li>the user interface needs to be in both English and French 053 <li>in source code, the programmers use both regular text snippets in 054 user-presentable English, and (occasionally) 'coder keys', according to the needs of each particular case 055 </ul> 056 057 Here is a style of <tt>ResultSet</tt> that can be used to implement this interface : 058 <P><table border=1 cellspacing=0 cellpadding=3> 059 <tr> 060 <th>BaseText</th><th>Locale</th><th>Translation</th> 061 </tr> 062 <tr><td>Fish And Chips</td><td>en</td><td>Fish And Chips</td></tr> 063 <tr><td>Fish And Chips</td><td>fr</td><td>Poisson et Frites</td></tr> 064 <tr><td>delete</td><td>en</td><td>delete</td></tr> 065 <tr><td>delete</td><td>fr</td><td>supprimer</td></tr> 066 <tr><td>add.edit.button</td><td>en</td><td>Add/Edit</td></tr> 067 <tr><td>add.edit.button</td><td>fr</td><td>Ajouter/Changer</td></tr> 068 </table> 069 070 <P>Only the last two rows use a "coder key". 071 The <tt>BaseText</tt> column holds either the coder key, or the user-presentable English. 072 The <tt>BaseText</tt> is the lookup key. The fact that there is 073 repetition of data between the <tt>BaseText</tt> and <tt>English</tt> columns is not a real duplication problem, 074 since <em>this is a <tt>ResultSet</tt>, not a table</em> - the underlying tables will not have such 075 repetition (if designed properly, of course). 076 077 <P>For example, such a <tt>ResultSet</tt> can be constructed from three underlying tables - 078 <tt>BaseText</tt>, <tt>Locale</tt>, and <tt>Translation</tt>. <tt>Translation</tt> is a cross-reference 079 table, with foreign keys to both <tt>BaseText</tt> and <tt>Locale</tt>. When such a scheme is 080 normalized, it will have no repeated data. (In underlying queries, however, the base 081 language will be necessarily treated differently than the other languages.) 082 083 <P>Upon startup, the tables are read, the above <tt>ResultSet</tt> is created and 084 stored in a <tt>private static Map</tt>, represented schematically as 085 <tt>Map[BaseText, Map[Locale, Translation]]</tt>. When a translation is required, 086 this <tt>Map</tt> is used as an in-memory lookup table. This avoids 087 repeated fetching from the database of trivial data that rarely changes. 088 089 <P><b>Note on Thread Safety</b> 090 <br>In the suggested implementation style, the <tt>private static Map</tt> that stores translation data is 091 <tt>static</tt>, and thus shared by multiple threads. Implementations are free to implement 092 any desired policy regarding thread safety, from relaxed to strict. A relaxed implementation 093 might completely ignore the possibility of a mistaken read/write, since no writes are expected in 094 production, or simply because the consequences are usually trivial. A strict implementation would 095 take the opposite approach, and demand that the <tt>private static Map</tt> be used in an fully 096 thread-safe manner. 097 */ 098 public interface Translator { 099 100 /** 101 Translate <tt>aBaseText</tt> into text appropriate for <tt>aLocale</tt>. 102 103 <P><tt>aBaseText</tt> is either user-presentable text in the base language of 104 development, or a "coder key" known only to the programmer. 105 106 <P>If <tt>aBaseText</tt> is unknown, then the implementation is free to define 107 any desired behavior. For example, this method might return 108 <ul> 109 <li><tt>aBaseText</tt> passed to this method, in its raw, untranslated form 110 <li><tt>aBaseText</tt> with special surrounding text, such as <tt>???some text???</tt>, with 111 leading and trailing characters 112 <li>a fixed <tt>String</tt> such as <tt>'???'</tt> or <tt>'?untranslated?'</tt> 113 <li>it is also possible for an implementation to throw a {@link RuntimeException} when 114 an item is missing, but this is not recommended for applications in production 115 </ul> 116 117 <P>If <tt>aBaseText</tt> is known, but there is no explicit translation for the 118 given {@link Locale}, then an implementation might choose to mimic the behavior of 119 {@link java.util.ResourceBundle}, and choose a translation from the "nearest available" 120 {@link Locale} instead. 121 122 @param aBaseText is not <tt>null</tt>, but may be empty 123 @param aLocale comes from the configured {@link LocaleSource}. 124 */ 125 String get(String aBaseText, Locale aLocale); 126 127 }