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 }