KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > tigris > scarab > tools > ScarabLocalizationTool


1 package org.tigris.scarab.tools;
2
3 /* ================================================================
4  * Copyright (c) 2000 CollabNet. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowlegement: "This product includes
19  * software developed by CollabNet (http://www.collab.net/)."
20  * Alternately, this acknowlegement may appear in the software itself, if
21  * and wherever such third-party acknowlegements normally appear.
22  *
23  * 4. The hosted project names must not be used to endorse or promote
24  * products derived from this software without prior written
25  * permission. For written permission, please contact info@collab.net.
26  *
27  * 5. Products derived from this software may not use the "Tigris" name
28  * nor may "Tigris" appear in their names without prior written
29  * permission of CollabNet.
30  *
31  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
32  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
33  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
34  * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
35  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
37  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
39  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
40  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  *
43  * ====================================================================
44  *
45  * This software consists of voluntary contributions made by many
46  * individuals on behalf of CollabNet.
47  */

48
49 import java.util.ArrayList JavaDoc;
50 import java.util.HashMap JavaDoc;
51 import java.util.Iterator JavaDoc;
52 import java.util.List JavaDoc;
53 import java.util.Locale JavaDoc;
54 import java.util.Map JavaDoc;
55 import java.util.MissingResourceException JavaDoc;
56 import java.util.ResourceBundle JavaDoc;
57
58 import javax.servlet.http.HttpServletRequest JavaDoc;
59
60 import org.apache.fulcrum.localization.LocaleTokenizer;
61 import org.apache.fulcrum.localization.Localization;
62 import org.apache.fulcrum.localization.LocalizationService;
63 import org.apache.turbine.RunData;
64 import org.apache.turbine.tool.LocalizationTool;
65 import org.tigris.scarab.tools.localization.Localizable;
66 import org.tigris.scarab.tools.localization.LocalizationKey;
67 import org.tigris.scarab.util.Log;
68 import org.tigris.scarab.util.ReferenceInsertionFilter;
69 import org.tigris.scarab.util.SkipFiltering;
70
71 /**
72  * Scarab-specific localiztion tool. Uses a specific property
73  * format to map a generic i10n key to a specific screen.
74  *
75  * For example, the $i10n.title on the screen:
76  * admin/AddPermission.vm would be in ScarabBundle_en.properties
77  * <blockquote><code><pre>
78  * admin/AddPermission.vm.Title
79  * </pre></code> </blockquote>
80  *
81  *
82  * @author <a HREF="mailto:dlr@collab.net">Daniel Rall </a>
83  * @author <a HREF="mailto:epugh@opensourceconnections.com">Eric Pugh </a>
84  */

85 public class ScarabLocalizationTool extends LocalizationTool
86 {
87     /**
88      * The Locale to be used, if the Resource could not be found in
89      * one of the Locales specified in the Browser's language preferences.
90      */

91     public static Locale JavaDoc DEFAULT_LOCALE = new Locale JavaDoc("en", "");
92
93     /**
94      * The portion of a key denoting the title property.
95      */

96     private static final String JavaDoc TITLE_PROP = "Title";
97
98     /**
99      * We need to keep a reference to the request's <code>RunData</code> so
100      * that we can extract the name of the target <i>after </i> the <code>Action</code>
101      * has run (which may have changed the target from its original value as a
102      * sort of internal redirect).
103      */

104     private RunData data;
105
106     /**
107      * Initialized by <code>init()</code>,
108      * cleared by <code>refresh()</code>.
109      */

110     private String JavaDoc bundlePrefix;
111     private String JavaDoc oldBundlePrefix;
112
113     /**
114      * Store the collection of locales to be used for ResourceBundle resolution.
115      * If the Class is instantiated from RunData, the collection contains all
116      * Locales in order of preference as specified in the Browser.
117      * If the Class is instantiated from a Locale, the collection contains
118      * just that Locale.
119      *
120      */

121     private List JavaDoc locales;
122
123     /**
124      * true: enables cross-site scripting filtering.
125      * @see resolveArgumentTemplates
126      * @see format(String, Object[])
127      */

128     private boolean filterEnabled = true;
129
130     /**
131      * Creates a new instance. Client should
132      * {@link #init(Object) initialize} the instance.
133      */

134     public ScarabLocalizationTool()
135     {
136     }
137
138     /**
139      * Return the localized property value.
140      * Take into account the Browser settings (in order of preference),
141      * the Turbine default settings and the System Locale,
142      * if the Turbine Default Locale is not defined.
143      */

144     public String JavaDoc get(Localizable key)
145     {
146         String JavaDoc theKey = key.toString();
147         return this.get(theKey);
148     }
149
150
151     /**
152      * Return the localized property value.
153      * Take into account the Browser settings (in order of preference),
154      * the Turbine default settings and the System Locale,
155      * if the Turbine Default Locale is not defined.
156      * Throws an Exception when an error occurs.
157      */

158     private String JavaDoc getInternal(String JavaDoc key)
159         throws Exception JavaDoc
160     {
161         String JavaDoc value = null;
162         
163         // Try with all defined "Browser"-Locales ordered by relevance
164
Iterator JavaDoc iter = locales.iterator();
165         while (value == null && iter.hasNext())
166         {
167             Locale JavaDoc locale = (Locale JavaDoc) iter.next();
168             value = resolveKey(key, locale);
169         }
170         return value;
171     }
172
173     
174     /**
175      * Return the localized property value.
176      * Take into account the Browser settings (in order of preference),
177      * the Turbine default settings and the System Locale,
178      * if the Turbine Default Locale is not defined.
179      * NOTE: Please don't use this method from the Java-code.
180      * It is intended for use with Velocity only!
181      * @deprecated Please use {@link #get(LocalizationKey)} instead
182      */

183     public String JavaDoc get(String JavaDoc key)
184     {
185         String JavaDoc value;
186         try
187         {
188             value = getInternal(key);
189             if (value == null)
190             {
191                 value = createMissingResourceValue(key);
192             }
193         }
194         catch(Exception JavaDoc e)
195         {
196             value = createBadResourceValue(key, e);
197         }
198         return value;
199     }
200
201     /**
202      * Return the localized property value.
203      * Take into account the Browser settings (in order of preference),
204      * the Turbine default settings and the System Locale,
205      * if the Turbine Default Locale is not defined.
206      * NOTE: Please don't use this method from the Java-code.
207      * It is intended for use with Velocity only!
208      * @deprecated Please use {@link #get(LocalizationKey)} instead
209      */

210     public String JavaDoc getIgnoreMissingResource(String JavaDoc key)
211     {
212         String JavaDoc value;
213         try
214         {
215             value = getInternal(key);
216             if(value == null)
217             {
218                 value = key;
219             }
220         }
221         catch(Exception JavaDoc e)
222         {
223             value = createBadResourceValue(key, e);
224         }
225         return value;
226     }
227     
228     /**
229      * Formats a localized value using the provided object.
230      *
231      * @param key The identifier for the localized text to retrieve,
232      * @param arg1 The object to use as {0} when formatting the localized text.
233      * @return Formatted localized text.
234      * @see #format(String, List)
235      */

236     public String JavaDoc format(String JavaDoc key, Object JavaDoc arg1)
237     {
238         return format(key, new Object JavaDoc[]{arg1});
239     }
240
241     /**
242      * Formats a localized value using the provided objects.
243      *
244      * @param key The identifier for the localized text to retrieve,
245      * @param arg1 The object to use as {0} when formatting the localized text.
246      * @param arg2 The object to use as {1} when formatting the localized text.
247      * @return Formatted localized text.
248      * @see #format(String, List)
249      */

250     public String JavaDoc format(String JavaDoc key, Object JavaDoc arg1, Object JavaDoc arg2)
251     {
252         return format(key, new Object JavaDoc[]{arg1, arg2});
253     }
254
255     /**
256      * Formats a localized value using the provided objects.
257      *
258      * @param key The identifier for the localized text to retrieve,
259      * @param arg1 The object to use as {0} when formatting the localized text.
260      * @param arg2 The object to use as {1} when formatting the localized text.
261      * @param arg3 The object to use as {2} when formatting the localized text.
262      * @return Formatted localized text.
263      * @see #format(String, List)
264      */

265     public String JavaDoc format(String JavaDoc key, Object JavaDoc arg1, Object JavaDoc arg2, Object JavaDoc arg3)
266     {
267         return format(key, new Object JavaDoc[]{arg1, arg2, arg3});
268     }
269
270     /**
271      * <p>Formats a localized value using the provided objects.</p>
272      *
273      * <p>ResourceBundle:
274      * <blockquote><code><pre>
275      * VelocityUsersNotWrong={0} out of {1} users can't be wrong!
276      * </pre></code> </blockquote>
277      *
278      * Template:
279      * <blockquote><code><pre>
280      * $l10n.format("VelocityUsersNotWrong", ["9", "10"])
281      * </pre></code> </blockquote>
282      *
283      * Result:
284      * <blockquote><code><pre>
285      * 9 out of 10 Velocity users can't be wrong!
286      * </pre></code></blockquote></p>
287      *
288      * @param key The identifier for the localized text to retrieve,
289      * @param args The objects to use as {0}, {1}, etc. when formatting the
290      * localized text.
291      * @return Formatted localized text.
292      */

293     public String JavaDoc format(String JavaDoc key, List JavaDoc args)
294     {
295         Object JavaDoc[] array = (args == null) ? null : args.toArray();
296         return format(key, array);
297     }
298
299     /**
300      * Allow us to be able to enable/disable our cross-site scripting filter
301      * when rendering something from the format() method. The default is to
302      * have it enabled.
303      */

304     public void setFilterEnabled(boolean v)
305     {
306         filterEnabled = v;
307     }
308
309     /**
310      * Whether our cross-site scripting filter is enabled.
311      */

312     public boolean isFilterEnabled()
313     {
314         return filterEnabled;
315     }
316
317     /**
318      * Formats a localized value using the provided objects.
319      * Take into account the Browser settings (in order of preference),
320      * the Turbine default settings and the System Locale,
321      * if the Turbine Default Locale is not defined.
322      *
323      * @param key The identifier for the localized text to retrieve,
324      * @param args The <code>MessageFormat</code> data used when formatting
325      * the localized text.
326      * @return Formatted localized text.
327      * @see #format(String, List)
328      */

329     public String JavaDoc format(String JavaDoc key, Object JavaDoc[] args)
330     {
331         String JavaDoc value = null;
332         resolveArgumentTemplates(args);
333         try
334         {
335             // try with the "Browser"-Locale
336
Iterator JavaDoc iter = locales.iterator();
337             while (value == null && iter.hasNext())
338             {
339                 Locale JavaDoc locale = (Locale JavaDoc) iter.next();
340                 value = formatKey(key, args, locale);
341             }
342             /*if (value == null)
343             {
344                 // try with the "Default"-Scope ??? This may be wrong (Hussayn)
345                 String prefix = getPrefix(null);
346                 setPrefix(DEFAULT_SCOPE + '.');
347                 try
348                 {
349                     value = super.format(key, args);
350                 }
351                 catch (MissingResourceException itsNotThere)
352                 {
353                     value = createMissingResourceValue(key);
354                 }
355                 setPrefix(prefix);
356             }*/

357         }
358         catch (Exception JavaDoc e)
359         {
360             value = createBadResourceValue(key, e);
361         }
362         return value;
363     }
364
365
366
367     /**
368      * Provides <code>$l10n.Title</code> to templates, grabbing it
369      * from the <code>title</code> property for the current template.
370      *
371      * @return The title for the template used in the current request, or
372      * <code>null</code> if title property was not found in
373      * the available resource bundles.
374      */

375     public String JavaDoc getTitle()
376     {
377         String JavaDoc title = findProperty(TITLE_PROP);
378         
379         return title;
380     }
381
382     /**
383      * Retrieves the localized version of the value of <code>property</code>.
384      *
385      * @param property
386      * The name of the property whose value to retrieve.
387      * @return The localized property value.
388      */

389     protected String JavaDoc findProperty(String JavaDoc property)
390     {
391         String JavaDoc value = null;
392
393         String JavaDoc templateName = data.getTarget().replace(',', '/');
394        
395
396         String JavaDoc l10nKey = property;
397         String JavaDoc prefix = getPrefix(templateName + '.');
398         if (prefix != null)
399         {
400             l10nKey = prefix + l10nKey;
401         }
402         value = get(l10nKey);
403         Log.get().debug( "ScarabLocalizationTool: Localized value is '"
404               + value
405               + '\'');
406         
407         return value;
408     }
409
410     /**
411      * Change the BundlePrefix. Keep the original value for later
412      * restore
413      * @param prefix
414      */

415     public void setBundlePrefix(String JavaDoc prefix)
416     {
417         oldBundlePrefix = bundlePrefix;
418         bundlePrefix = prefix;
419     }
420
421     /**
422      * Restore the old Bundle Prefix to it's previous value.
423      */

424     public void restoreBundlePrefix()
425     {
426         bundlePrefix = oldBundlePrefix;
427     }
428
429
430     /**
431      * Get the default ResourceBundle name
432      */

433     protected String JavaDoc getBundleName()
434     {
435         String JavaDoc name = Localization.getDefaultBundleName();
436         return (bundlePrefix == null) ? name : bundlePrefix + name;
437     }
438
439     /**
440      * Gets the primary locale.
441      * The primary locale is the locale which will be choosen
442      * at first from the set of Locales which are accepted by the user
443      * as defined on the Browser language preferrences.
444      * @return The primary locale currently in use.
445      */

446     public Locale JavaDoc getPrimaryLocale()
447     {
448         return (locales == null || locales.size() == 0) ? super.getLocale()
449                 : (Locale JavaDoc) locales.iterator().next();
450     }
451
452     // ---- ApplicationTool implementation ----------------------------------
453

454     /**
455      * Initialize the tool. Within the turbine pull service this tool is
456      * initialized with a RunData. However, the tool can also be initialized
457      * with a Locale.
458      */

459     public void init(Object JavaDoc obj)
460     {
461         super.init(obj);
462         if (obj instanceof RunData)
463         {
464             data = (RunData) obj;
465             locales = getPreferredLocales();
466         }
467         else if (obj instanceof Locale JavaDoc)
468         {
469             locales = new ArrayList JavaDoc();
470             locales.add(obj);
471             locales.add(DEFAULT_LOCALE);
472             locales.add(null);
473         }
474     }
475
476     /**
477      * Reset this instance to initial values.
478      * Probably needed for reuse of ScarabLocalizationTool Instances.
479      */

480     public void refresh()
481     {
482         super.refresh();
483         data = null;
484         bundlePrefix = null;
485         oldBundlePrefix = null;
486         locales = null;
487         setFilterEnabled(true);
488     }
489
490
491     // ===========================
492
// Private utility methods ...
493
// ===========================
494

495     /**
496      * Utility method: Get a Collection of possible locales
497      * to be used as specified in the Browser settings. Adds
498      * the DEFAULT_LOCALE as last resort to the list.
499      * Additionally adds a final null to the list. So be prepared
500      * to see a null pointer when you iterate through the list.
501      * @return
502      */

503     private List JavaDoc getPreferredLocales()
504     {
505         List JavaDoc result = new ArrayList JavaDoc(3);
506         String JavaDoc localeAsString = getBrowserLocalesAsString();
507         LocaleTokenizer localeTokenizer = new LocaleTokenizer(localeAsString);
508         while (localeTokenizer.hasNext())
509         {
510             Locale JavaDoc browserLocale = (Locale JavaDoc) localeTokenizer.next();
511             Locale JavaDoc finalLocale = getFinalLocaleFor(browserLocale);
512             if (finalLocale != null)
513             {
514                 result.add(finalLocale);
515             }
516         }
517         result.add(DEFAULT_LOCALE);
518         result.add(null);
519         return result;
520     }
521
522
523     /**
524      * Contains a map of Locales which support given
525      * browserLocales.
526      */

527     static private Map JavaDoc supportedLocaleMap = new HashMap JavaDoc();
528     /**
529      * Contains a map of Locales which do NOT support given
530      * browserLocales.
531      */

532     static private Map JavaDoc unsupportedLocaleMap = new HashMap JavaDoc();
533
534     /**
535      * Return the locale, which will be used to resolve
536      * keys of the given browserLocale. This method returns
537      * null, when Scarab does not directly support the
538      * browserLocale.
539      * @param browserLocale
540      * @return
541      */

542     private Locale JavaDoc getFinalLocaleFor(Locale JavaDoc browserLocale)
543     {
544         Locale JavaDoc result = (Locale JavaDoc) supportedLocaleMap.get(browserLocale);
545         if (result == null)
546         {
547             if (unsupportedLocaleMap.get(browserLocale) == null)
548             {
549                 ResourceBundle JavaDoc bundle;
550                 try {
551                     bundle = ResourceBundle.getBundle(
552                              getBundleName(), browserLocale);
553                 }
554                 catch (Exception JavaDoc e)
555                 {
556                   // [HD] This should not happen, but it does happen;
557
// The problem raises when the system locale is not
558
// supported by Scarab. This was reported on Windows
559
// systems. This needs to be further investigated.
560
// setting bundle to null here enforces usage of the
561
// default ResourceBundle (en-US)
562
bundle = null;
563                 }
564
565                 if (bundle != null)
566                 {
567                     Locale JavaDoc finalLocale = bundle.getLocale();
568                     String JavaDoc initialLanguage = browserLocale.getLanguage();
569                     String JavaDoc finalLanguage = finalLocale.getLanguage();
570                     if (initialLanguage.equals(finalLanguage))
571                     {
572                         result = finalLocale;
573                         supportedLocaleMap.put(browserLocale, finalLocale);
574                     }
575                     else
576                     {
577                         unsupportedLocaleMap.put(browserLocale, finalLocale);
578                     }
579                 }
580                 else
581                 {
582                     Log.get().error("ScarabLocalizationTool: ResourceBundle '" + getBundleName()
583                             + "' -> not resolved for Locale '"
584                             + browserLocale
585                             + "'.");
586                 }
587             }
588         }
589         return result;
590     }
591
592     /**
593      * Utility method: Get the content of the Browser localizationj settings.
594      * Return an empty String when no Browser settings are defined.
595      * @param acceptLanguage
596      * @param request
597      */

598     private String JavaDoc getBrowserLocalesAsString()
599     {
600         String JavaDoc acceptLanguage = LocalizationService.ACCEPT_LANGUAGE;
601         HttpServletRequest JavaDoc request = data.getRequest();
602         String JavaDoc browserLocaleAsString = request.getHeader(acceptLanguage);
603         if (browserLocaleAsString == null)
604         {
605             browserLocaleAsString = "";
606         }
607         return browserLocaleAsString;
608     }
609
610     /**
611      * Utility method: Resolve a given key using the given Locale.
612      * If the key can not be resolved, return null
613      * @param key
614      * @param locale
615      * @return
616      */

617     private String JavaDoc resolveKey(String JavaDoc key, Locale JavaDoc locale)
618     {
619         String JavaDoc value;
620         try
621         {
622             value = Localization.getString(getBundleName(), locale, key);
623         }
624         catch (MissingResourceException JavaDoc noKey)
625         {
626             // No need for logging (already done in base class).
627
value = null;
628         }
629         return value;
630     }
631
632
633     /**
634      * Utility method: Resolve a given key using the given Locale and apply
635      * the resource formatter. If the key can not be resolved,
636      * return null
637      * @param key
638      * @param args
639      * @param locale
640      * @return
641      */

642     private String JavaDoc formatKey(String JavaDoc key, Object JavaDoc[] args, Locale JavaDoc locale)
643     {
644         String JavaDoc value;
645         try
646         {
647             value = Localization.format(getBundleName(), locale, key, args);
648         }
649         catch (MissingResourceException JavaDoc noKey)
650         {
651             value = null;
652         }
653         return value;
654     }
655
656     /**
657      * Utility method: Resolve $variables placed within the args.
658      * Used before actually calling the resourceBundle formatter.
659      * @param args
660      * @return a cloned args list, or args when
661      * filtering is disabled. If args is null, also
662      * return null.
663      */

664     private Object JavaDoc[] resolveArgumentTemplates(Object JavaDoc[] args)
665     {
666         // we are going to allow html text within resource bundles. This
667
// avoids problems in translations when links or other html tags
668
// would result in an unnatural breakup of the text. We need
669
// to apply the filtering here on the arguments which might contain
670
// user entered data, if we are going to skip the filtering later.
671

672         Object JavaDoc[] result;
673         if (isFilterEnabled() && args != null && args.length > 0)
674         {
675             result = new Object JavaDoc[args.length];
676             for (int i = 0; i < args.length; i++)
677             {
678                 Object JavaDoc obj = args[i];
679                 // we don't filter Number, because these are sometimes passed
680
// to message formatter in order to make a choice. Converting
681
// the number to a String will cause error
682
if (obj != null)
683                 {
684                     if (!( (obj instanceof SkipFiltering)
685                            || (obj instanceof Number JavaDoc))
686                     )
687                     {
688                         obj = ReferenceInsertionFilter.filter(obj.toString());
689                     }
690                 }
691                 result[i] = obj;
692             }
693         }
694         else
695         {
696             result = args;
697         }
698         return result;
699     }
700
701     /**
702      * Utility method: create a Pseudovalue when the key
703      * has no resolution at all.
704      * @param key
705      * @return
706      */

707     private String JavaDoc createMissingResourceValue(String JavaDoc key)
708     {
709         String JavaDoc value;
710         value = "ERROR! Missing resource ("
711                 + key
712                 + ")("
713                 + Locale.getDefault()
714                 + ")";
715         Log.get().error(
716                 "ScarabLocalizationTool: ERROR! Missing resource: " + key);
717         return value;
718     }
719
720     /**
721      * Utility method: create a Pseudovalue when the key
722      * can not be used as resource key.
723      * @param key
724      * @param e
725      * @return
726      */

727     private String JavaDoc createBadResourceValue(String JavaDoc key, Exception JavaDoc e)
728     {
729         String JavaDoc value;
730         value = "ERROR! Bad resource (" + key + ")";
731         Log.get().error( "ScarabLocalizationTool: ERROR! Bad resource: " + key
732                 + ". See log for details.", e);
733         return value;
734     }
735
736
737     /**
738      * Extract a message from an exception. This method checks, if
739      * the exception is Localizable. If so, we now can retrieve the localized exception message.
740      * Otherwise we retrieve the standard message via e.getLocalizedMessage().
741      * @param e
742      * @return
743      * throws NullPointerException if t is <code>null</code>
744      */

745     public String JavaDoc getMessage(Throwable JavaDoc t)
746     {
747         String JavaDoc result;
748         if(t instanceof Localizable)
749         {
750              result = ((Localizable) t).getMessage(this);
751         }
752         else
753         {
754             // [HD] note we reuse getLocalizedMessage() in case the exception
755
// coming from a third party library is also localized.
756
// [JEROME] After rethinking this, I am not sure that this else {}
757
// would work. The intent is nice but the implementation perhaps
758
// naive. As I said in the Localizable javadoc, implementation of
759
// getLocalizedMessage() probably requires the implementation of
760
// an IoC pattern. That means somebody would have to say to the
761
// third party library which locale to use for the localization.
762
// Perhaps register it to the instance, or to a global Localizer,
763
// or anything that the getLocalizedMessage() implementation
764
// would use to properly localize. Just calling getLocalizedMessage()
765
// wouldn't work without this prior registration, which might be
766
// library dependent.
767
result = t.getLocalizedMessage();
768         }
769         return result;
770     }
771
772
773 }
774
Popular Tags