/[schmitzm]/trunk/src/skrueger/i8n/Translation.java
ViewVC logotype

Contents of /trunk/src/skrueger/i8n/Translation.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 607 - (show annotations)
Wed Dec 9 15:13:42 2009 UTC (15 years, 2 months ago) by alfonx
Original Path: branches/2.0-RC1/src/skrueger/i8n/Translation.java
File size: 12763 byte(s)
Keine Ahnung was er da gebrancht hat.. der stand der dateien war weder trunk, noch der 1.0-gt26 branch... ich hab die dateien jetzt händisch auf den richtigen stand gebracht und comitte

1 /*******************************************************************************
2 * Copyright (c) 2009 Martin O. J. Schmitz.
3 *
4 * This file is part of the SCHMITZM library - a collection of utility
5 * classes based on Java 1.6, focusing (not only) on Java Swing
6 * and the Geotools library.
7 *
8 * The SCHMITZM project is hosted at:
9 * http://wald.intevation.org/projects/schmitzm/
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 3
14 * of the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License (license.txt)
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 * or try this link: http://www.gnu.org/licenses/lgpl.html
25 *
26 * Contributors:
27 * Martin O. J. Schmitz - initial API and implementation
28 * Stefan A. Krüger - additional utility classes
29 ******************************************************************************/
30 package skrueger.i8n;
31
32 import java.awt.event.ActionEvent;
33 import java.awt.event.ActionListener;
34 import java.beans.PropertyChangeEvent;
35 import java.beans.PropertyChangeListener;
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Locale;
41 import java.util.Random;
42 import java.util.WeakHashMap;
43
44 import javax.swing.JComponent;
45
46 import org.apache.log4j.Logger;
47 import org.geotools.util.WeakHashSet;
48 import org.opengis.util.InternationalString;
49
50 import skrueger.geotools.Copyable;
51
52 /**
53 * Represents a {@link HashMap} of translations. toString() returns the
54 * appropriate translation
55 *
56 * @author @author <a href="mailto:[email protected]">Stefan Alfons
57 * Kr&uuml;ger</a>
58 */
59
60 public class Translation extends HashMap<String, String> implements
61 Copyable<Translation> {
62 public static final String LOCALECHANGE_PROPERTY = "localechange";
63 public static final String NO_TRANSLATION = "NO TRANSLATION";
64 public static final String DEFAULT_KEY = "default";
65 static final Logger LOGGER = Logger.getLogger(Translation.class);
66 static String activeLang = Locale.getDefault().getLanguage();
67
68 static protected WeakHashSet<PropertyChangeListener> listeners = new WeakHashSet<PropertyChangeListener>(
69 PropertyChangeListener.class);
70
71 static {
72
73 // TODO default aus Locale auslesen und mit möglichen vergleichen...
74 // mmm.. vor laden von atlasml immer DEFAULT_KEY, also hier nicht
75
76 // Get default locale
77 Locale locale = Locale.getDefault();
78 setActiveLang(locale.getLanguage());
79 }
80
81 private WeakHashSet<ActionListener> actionListeners = new WeakHashSet<ActionListener>(
82 ActionListener.class);
83
84 @Override
85 /*
86 * @comment To make a copy of a translation see methods toOneLine() and
87 * fromOneLine()
88 */
89 public Translation clone() {
90 throw new RuntimeException("use copy()");
91 // return (Translation) super.clone();
92 }
93
94 /**
95 * Get the two-letter language sting that is active
96 */
97 public static String getActiveLang() {
98 return activeLang;
99 }
100
101 /**
102 * Set up the {@link Translation}-system to use language. If a change is
103 * performed, events are fired to listeners. Nothing is done if the new
104 * language equals the old language. The system's default locale is changed.
105 *
106 * @param newLang
107 * The ISO Code of the new active language
108 */
109 public static void setActiveLang(String newLang) {
110 setActiveLang(newLang, true);
111 }
112
113 /**
114 * Set up the {@link Translation}-system to use language. If a change is
115 * performed, events are fired to listeners. Nothing is done if the new
116 * language equals the old language.
117 *
118 * @param newLang
119 * The ISO Code of the new active language
120 *
121 * @param setDefaultLocale
122 * Shall the system's default locale be changed?
123 */
124 public static void setActiveLang(String newLang, boolean setDefaultLocale) {
125 if (getActiveLang().equals(newLang)) {
126 return;
127 }
128
129 if (!I8NUtil.isValidISOLangCode(newLang)) {
130 throw new IllegalArgumentException("'" + newLang
131 + "' is not a valid ISO language code.");
132 }
133
134 Locale newLocale = new Locale(newLang);
135 if (setDefaultLocale)
136 Locale.setDefault(newLocale);
137
138 /**
139 * Setting default locale for Swing JComponents to work around bug
140 * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4884480
141 */
142 JComponent.setDefaultLocale(newLocale);
143
144 Translation.activeLang = newLang;
145
146 fireLocaleChangeEvents();
147
148 LOGGER.info("skrueger.i8n.Translation switched ActiveLang to "
149 + newLang);
150 }
151
152 /**
153 * Initializes a new {@link Translation} with a default translation if a
154 * simple text is passed. If a "oneLine" text is parsed, it is interpreted.
155 * Other translations may be added later - this is a HashMap<br/>
156 *
157 * @param defaultTranslation
158 *
159 * @see public Translation(List<String> languages, String
160 * defaultTranslation) {
161 *
162 */
163 public Translation(String defaultTranslation) {
164
165 fromOneLine(defaultTranslation);
166
167 }
168
169 /**
170 * Initializes a new {@link Translation}, an uses the given String to
171 * initialize the {@link Translation} for all languages codes passed.
172 *
173 * The translations can be changed later
174 */
175 public Translation(List<String> languages, String defaultTranslation) {
176 // put(DEFAULT_KEY, defaultTranslation);
177 if (languages == null) {
178 put(DEFAULT_KEY, defaultTranslation);
179 } else
180 for (String code : languages) {
181 if (code.equals(getActiveLang())) {
182 put(code, defaultTranslation);
183 }
184 }
185 }
186
187 /**
188 * Sometimes Translations are optional, like for keywords.
189 */
190 public Translation() {
191 }
192
193 /**
194 * Fills the {@link Translation} with the values coded into the String
195 * Format of {@link String} is: "de{Baum}en{tree}"
196 * <p>
197 * <ul>
198 * <li>If <code>oneLineCoded</code> is empty or null, NO TRANSLATION is set.
199 * <li>If format can't be recognized, the {@link String} is interpreted as
200 * the translation in the <code>{@value #DEFAULT_KEY}</code> language
201 *
202 * @author Stefan Alfons Krüger
203 */
204 public void fromOneLine(final String oneLineCoded) {
205
206 clear();
207
208 try {
209
210 if ((oneLineCoded == null) || (oneLineCoded.equals(""))) {
211 put(DEFAULT_KEY, "");
212 return;
213 }
214
215 if (oneLineCoded.indexOf("}") == -1) {
216 // log.warn("The String '"+oneLineCoded+"' is not in oneLine coded => put(DEFAULT_KEY,oneLineCoded);");
217 put(DEFAULT_KEY, oneLineCoded);
218 }
219
220 String eatUp = oneLineCoded;
221 while (eatUp.indexOf("}") != -1) {
222 String substring = eatUp.substring(0, eatUp.indexOf("}"));
223
224 // log.debug("substring = "+substring);
225 String key = substring.substring(0, substring.indexOf("{"));
226 String value = substring.substring(substring.indexOf("{") + 1,
227 substring.length());
228 // log.debug("key="+key);
229 // log.debug("value="+value);
230 put(key, value);
231 eatUp = eatUp.substring(eatUp.indexOf("}") + 1);
232 }
233 } catch (Exception e) {
234 LOGGER.warn("Error while reading the oneLineCode '" + oneLineCoded
235 + "'", e);
236 LOGGER.warn("Translation will be empty!");
237 }
238 }
239
240 /**
241 * Exports the Translations to a String of the Format: "de{Baum}en{tree}"
242 *
243 * @author Stefan Alfons Krüger
244 */
245 public String toOneLine() {
246 return I8NUtil.toOneLine(this);
247 }
248
249 /**
250 * Returns the right translation by using the {@link #activeLang} field. If
251 * no translation is set, an ugly String {@link #NO_TRANSLATION} will re
252 * returned. This might be changed for the final release. If the correct
253 * language was not found, any entry in the {@link Translation}
254 * {@link HashMap} will be returned, that contains more than an empty
255 * string.
256 */
257 @Override
258 public String toString() {
259 if (get(activeLang) != null) {
260 return get(activeLang);
261 }
262 // ****************************************************************************
263 // MS: The ISDSS needs the concept of the default lang!! So I took the
264 // following in again!!
265 // ****************************************************************************
266 // else return "";
267 // //****************************************************************************
268 // // The following is commented out.. the concept of the default lang
269 // seems to be bad....
270 // //****************************************************************************
271 // MS:
272 else {
273 if (get(DEFAULT_KEY) != null) {
274 return get(DEFAULT_KEY);
275 }
276
277 // log.debug("return first best <> '' ");
278 if (size() > 0)
279 for (String s : values()) {
280 if ((s != null) && (s.trim().length() > 0))
281 return s;
282 }
283 }
284 // log.warn("No translation found!");
285 return NO_TRANSLATION;
286 }
287
288 /**
289 * {@link PropertyChangeListener} can be registered to be informed when the
290 * {@link Locale} changed.<br>
291 * The listeners are kept in a {@link WeakHashMap}, so you have to keep a
292 * reference to the listener or it will be removed!
293 *
294 * @param propertyChangeListener
295 * A {@link PropertyChangeListener} that will be called when
296 * {@link #setActiveLang(String)} changes the language.
297 */
298 public static void addLocaleChangeListener(
299 PropertyChangeListener propertyChangeListener) {
300 listeners.add(propertyChangeListener);
301 }
302
303 /**
304 * {@link PropertyChangeListener} can be registered to be informed when the
305 * {@link Locale} changed.<br>
306 * The listeners are kept in a {@link WeakHashMap}, so you have to keep a
307 * reference to the listener or it will be removed!
308 *
309 * @param propertyChangeListener
310 * A {@link PropertyChangeListener} that will be called when
311 * {@link #setActiveLang(String)} changes the language.
312 */
313 public static boolean removeLocaleChangeListener(
314 PropertyChangeListener propertyChangeListener) {
315 return listeners.remove(propertyChangeListener);
316 }
317
318 /**
319 * Informs all registered {@link PropertyChangeListener}s about a change of
320 * the the {@link Locale}.
321 */
322 public static void fireLocaleChangeEvents() {
323 PropertyChangeEvent pce = new PropertyChangeEvent(new Translation(
324 new ArrayList<String>(), "fakeSource"), LOCALECHANGE_PROPERTY,
325 null, getActiveLang());
326 for (PropertyChangeListener pcl : listeners) {
327 if (pcl != null)
328 pcl.propertyChange(pce);
329 }
330 }
331
332 /**
333 * The listeneras are stored in a {@link WeakHashSet}! So you HAVE TO KEEP a
334 * reference as long as you need the listener.
335 */
336 public void addTranslationChangeListener(ActionListener actionListener) {
337 if (actionListeners.add(actionListener)) {
338 LOGGER
339 .debug("registering a new translationChangeActionListener in the WeakHashSet");
340 }
341 }
342
343 /**
344 * The listeneras are stored in a {@link WeakHashSet}! You don't have to
345 * remove the listener, as long as you throw away the reference to the
346 * listener.
347 */
348 public boolean removeTranslationChangeListener(ActionListener actionListener) {
349 return actionListeners.remove(actionListener);
350 }
351
352 public void fireTranslationChangedEvents(String lang) {
353 ActionEvent ae = new ActionEvent(this, new Random().nextInt(), lang);
354
355 final Iterator<ActionListener> iterator = actionListeners.iterator();
356 while (iterator.hasNext()) {
357 ActionListener al = iterator.next();
358 al.actionPerformed(ae);
359 }
360 }
361
362 @Override
363 public String put(String lang, String value) {
364 String result = super.put(lang, value);
365 fireTranslationChangedEvents(lang);
366 return result;
367 }
368
369 public void fromOneLine(InternationalString iString) {
370 if (iString != null)
371 fromOneLine(iString.toString());
372 else
373 fromOneLine((String) null);
374 }
375
376 /**
377 * Copy this {@link Translation} to another {@link Translation} e.g. for
378 * editing
379 *
380 * @return the destination {@link Translation}
381 */
382 @Override
383 public Translation copyTo(Translation translation2) {
384
385 if (translation2 == null)
386 // throw new IllegalArgumentException(
387 // "Target translation may not be null.");
388 return copy();
389 for (String s : keySet()) {
390 translation2.put(s, get(s));
391 }
392
393 return translation2;
394 }
395
396 @Override
397 public Translation copy() {
398 return copyTo(new Translation());
399 }
400
401 /**
402 * Checks if the {@link String}s stored in the {@link Translation} are all
403 * valid.
404 *
405 * @return <code>true</code> if all good
406 */
407 public static boolean checkValid(Translation translationToCheck) {
408
409 for (String l : translationToCheck.values()) {
410
411 if (l.contains("{") || l.contains("}")) {
412
413 return false;
414 }
415 }
416 return true;
417 }
418
419 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26