001 /**
002 * Jetrix TetriNET Server
003 * Copyright (C) 2001-2004,2010 Emmanuel Bourg
004 *
005 * This program is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU General Public License
007 * as published by the Free Software Foundation; either version 2
008 * of the License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program; if not, write to the Free Software
017 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
018 */
019
020 package net.jetrix;
021
022 import java.util.*;
023 import java.text.*;
024
025 /**
026 * Helper class to handle and retrieve localized strings.
027 *
028 * @author Emmanuel Bourg
029 * @version $Revision: 846 $, $Date: 2010-05-03 17:29:44 +0200 (lun., 03 mai 2010) $
030 */
031 public class Language
032 {
033 /** The names of the resource bundles imported. */
034 private Set<String> bundleNames = new HashSet<String>();
035
036 private Map<Locale, MultiResourceBundle> bundles = new HashMap<Locale, MultiResourceBundle>();
037
038 private static Language instance = new Language();
039
040 /** The default resource bundle containing the server messages. */
041 private static final String DEFAULT_RESOURCE = "jetrix";
042
043 private Language()
044 {
045 addResources(DEFAULT_RESOURCE);
046 }
047
048 /**
049 * Return the unique instance of this class.
050 */
051 public static Language getInstance()
052 {
053 return instance;
054 }
055
056 /**
057 * Register an extra set of localized messages.
058 *
059 * @param name the base name of the resource bundle
060 * @since 0.3
061 */
062 public void addResources(String name)
063 {
064 bundleNames.add(name);
065 }
066
067 /**
068 * Load and return the <tt>ResourceBundle</tt> for the specified locale.
069 * Bundles are cached in a local Map.
070 *
071 * @param locale the locale of the returned bundle if available
072 */
073 protected ResourceBundle load(Locale locale)
074 {
075 MultiResourceBundle bundle = new MultiResourceBundle(locale);
076 bundles.put(locale, bundle);
077 return bundle;
078 }
079
080 /**
081 * Tell if the specified locale has a corresponding resource file available.
082 *
083 * @param locale the locale to test
084 *
085 * @return <tt>true</tt> if the locale is supported, <tt>false</tt> if not.
086 */
087 public static boolean isSupported(Locale locale)
088 {
089 MultiResourceBundle bundle = instance.bundles.get(locale);
090 if (bundle == null)
091 {
092 bundle = instance.new MultiResourceBundle(locale);
093 }
094 return bundle.isSupported();
095 }
096
097 /**
098 * Return the list of languages supported by the server.
099 */
100 public static Collection<Locale> getLocales()
101 {
102 Collection<Locale> locales = new ArrayList<Locale>();
103
104 for (String language : Locale.getISOLanguages())
105 {
106 Locale locale = new Locale(language);
107 if (isSupported(locale))
108 {
109 locales.add(locale);
110 }
111 }
112
113 return locales;
114 }
115
116 /**
117 * Return the specified localized text for a given locale.
118 *
119 * @param key the text key in the resource bundle
120 * @param locale the locale of the message
121 */
122 public static String getText(String key, Locale locale)
123 {
124 try
125 {
126 ResourceBundle bundle = instance.bundles.get(locale);
127 if (bundle == null)
128 {
129 bundle = instance.load(locale);
130 }
131
132 return bundle.getString(key);
133 }
134 catch (Exception e)
135 {
136 return "[" + locale + ":" + key + "]";
137 }
138 }
139
140 /**
141 * Return the specified localized text for a given locale and replace the
142 * parameters with an array of arguments.
143 *
144 * @since 0.2
145 *
146 * @param key the text key in the resource bundle
147 * @param locale the locale of the message
148 * @param arguments the array of arguments
149 */
150 public static String getText(String key, Locale locale, Object ... arguments)
151 {
152 // localize the arguments
153 Object[] arguments2 = new Object[arguments.length];
154 for (int i = 0; i < arguments.length; i++)
155 {
156 arguments2[i] = getLocalizedArgument(locale, arguments[i]);
157 }
158
159 return MessageFormat.format(getText(key, locale), arguments2);
160 }
161
162 /**
163 * Transforms a localized argument into its actual value. Localized
164 * arguments start with the "key:" prefix and refers to another message
165 * in the resource bundle.
166 *
167 * @since 0.3
168 *
169 * @param locale the target locale
170 * @param argument the argument to transform
171 */
172 private static Object getLocalizedArgument(Locale locale, Object argument)
173 {
174 if (argument instanceof String && ((String) argument).startsWith("key:"))
175 {
176 return getText(((String) argument).substring(4), locale);
177 }
178 else
179 {
180 return argument;
181 }
182 }
183
184 /**
185 * A resource bundle merging several property based resource bundles.
186 *
187 * @since 0.3
188 */
189 private class MultiResourceBundle extends ResourceBundle
190 {
191 private Locale locale;
192
193 private MultiResourceBundle(Locale locale)
194 {
195 this.locale = locale;
196 }
197
198 private PropertyResourceBundle getPropertyResourceBundle(String name) {
199 try
200 {
201 return (PropertyResourceBundle) PropertyResourceBundle.getBundle(name, locale);
202 }
203 catch (MissingResourceException e)
204 {
205 return null;
206 }
207 }
208
209 protected Object handleGetObject(String key)
210 {
211 for (String name : bundleNames)
212 {
213 PropertyResourceBundle bundle = getPropertyResourceBundle(name);
214 if (bundle != null)
215 {
216 Object value = bundle.handleGetObject(key);
217 if (value != null)
218 {
219 return value;
220 }
221 }
222 }
223
224 return null;
225 }
226
227 public Enumeration<String> getKeys()
228 {
229 return null;
230 }
231
232 /**
233 * Checks if at least one of the underlying resource bundles supports
234 * the locale assigned to this bundle.
235 */
236 public boolean isSupported()
237 {
238 for (String name : bundleNames)
239 {
240 PropertyResourceBundle bundle = getPropertyResourceBundle(name);
241 if (bundle != null && bundle.getLocale().equals(locale))
242 {
243 return true;
244 }
245 }
246
247 return false;
248 }
249 }
250 }