3 * Copyright © 2008 David Roden
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 package net.pterodactylus.jsite.i18n;
22 import java.awt.event.InputEvent;
23 import java.awt.event.KeyEvent;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.lang.reflect.Field;
27 import java.text.MessageFormat;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.MissingResourceException;
32 import java.util.Properties;
33 import java.util.StringTokenizer;
35 import javax.swing.KeyStroke;
37 import net.pterodactylus.util.io.Closer;
40 * Class that handles i18n.
42 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
47 /** List of I18nables that are notified when the language changes. */
48 private static final List<I18nable> i18nables = new ArrayList<I18nable>();
50 /** The current locale. */
51 private static Locale currentLocale;
53 /** The default language. */
54 private static Properties defaultLanguage;
56 /** The current language. */
57 private static Properties currentLanguage;
60 defaultLanguage = new Properties();
61 InputStream inputStream = null;
63 inputStream = I18n.class.getResourceAsStream("jSite.properties");
64 if (inputStream != null) {
65 defaultLanguage.load(inputStream);
67 } catch (IOException e) {
68 /* something is fucked. */
70 setLocale(Locale.getDefault(), false);
74 * Returns the translated value for a key. The translated values may contain
75 * placeholders that are replaced with the given parameters.
81 * The parameters in case the translated value contains
83 * @return The translated message, or the key itself if no translation could
86 public static String get(String key, Object... parameters) {
88 value = currentLanguage.getProperty(key);
90 System.err.println("please fix “" + key + "”!");
93 if ((parameters != null) && (parameters.length > 0)) {
94 return MessageFormat.format(value, parameters);
100 * Returns the keycode from the value of the given key. You can specify the
101 * constants in {@link KeyEvent} in the properties file, e.g. VK_S for the
102 * keycode ‘s’ when used for mnemonics.
105 * The key under which the keycode is stored
106 * @return The keycode
108 public static int getKey(String key) {
109 String value = currentLanguage.getProperty(key);
110 if ((value != null) && value.startsWith("VK_")) {
112 Field field = KeyEvent.class.getField(value);
113 return field.getInt(null);
114 } catch (SecurityException e) {
116 } catch (NoSuchFieldException e) {
118 } catch (IllegalArgumentException e) {
120 } catch (IllegalAccessException e) {
124 System.err.println("please fix “" + key + "”!");
125 return KeyEvent.VK_UNDEFINED;
129 * Returns a key stroke for use with swing accelerators.
132 * The key of the key stroke
133 * @return The key stroke, or <code>null</code> if no key stroke could be
134 * created from the translated value
136 public static KeyStroke getKeyStroke(String key) {
137 String value = currentLanguage.getProperty(key);
141 StringTokenizer keyTokens = new StringTokenizer(value, "+- ");
142 int modifierMask = 0;
143 while (keyTokens.hasMoreTokens()) {
144 String keyToken = keyTokens.nextToken();
145 if ("ctrl".equalsIgnoreCase(keyToken)) {
146 modifierMask |= InputEvent.CTRL_DOWN_MASK;
147 } else if ("alt".equalsIgnoreCase(keyToken)) {
148 modifierMask |= InputEvent.ALT_DOWN_MASK;
149 } else if ("shift".equalsIgnoreCase(keyToken)) {
150 modifierMask |= InputEvent.SHIFT_DOWN_MASK;
152 if (keyToken.startsWith("VK_")) {
154 Field field = KeyEvent.class.getField(keyToken);
155 return KeyStroke.getKeyStroke(field.getInt(null), modifierMask);
156 } catch (SecurityException e) {
158 } catch (NoSuchFieldException e) {
160 } catch (IllegalArgumentException e) {
162 } catch (IllegalAccessException e) {
166 return KeyStroke.getKeyStroke(keyToken.charAt(0), modifierMask);
173 * Sets the current locale.
176 * The new locale to use
178 public static void setLocale(Locale newLocale) {
179 setLocale(newLocale, true);
183 * Sets the current locale.
186 * The new locale to use
188 * <code>true</code> to notify registered {@link I18nable}s
189 * after the language was changed
191 private static void setLocale(Locale newLocale, boolean notify) {
192 currentLocale = newLocale;
193 InputStream inputStream = null;
195 currentLanguage = new Properties(defaultLanguage);
196 if (newLocale == Locale.ENGLISH) {
202 inputStream = I18n.class.getResourceAsStream("jSite_" + newLocale.getLanguage() + ".properties");
203 if (inputStream != null) {
204 currentLanguage.load(inputStream);
209 } catch (MissingResourceException mre1) {
210 currentLocale = Locale.ENGLISH;
211 } catch (IOException ioe1) {
212 currentLocale = Locale.ENGLISH;
214 Closer.close(inputStream);
219 * Returns the current locale.
221 * @return The current locale
223 public static Locale getLocale() {
224 return currentLocale;
228 * Finds all available locales.
230 * @return All available locales
232 public static List<Locale> findAvailableLanguages() {
233 List<Locale> availableLanguages = new ArrayList<Locale>();
234 availableLanguages.add(Locale.ENGLISH);
235 availableLanguages.add(Locale.GERMAN);
236 return availableLanguages;
240 * Registers the given I18nable to be updated when the language is changed.
243 * The i18nable to register
245 public static void registerI18nable(I18nable i18nable) {
246 i18nables.add(i18nable);
250 * Deregisters the given I18nable to be updated when the language is
254 * The i18nable to register
256 public static void deregisterI18nable(I18nable i18nable) {
257 i18nables.remove(i18nable);
265 * Notifies all registered {@link I18nable}s that the language was changed.
267 private static void notifyI18nables() {
268 for (I18nable i18nable: i18nables) {
269 i18nable.updateI18n();