/** * Copyright (c) 2009 - 2010 AppWork UG(haftungsbeschränkt) <e-mail@appwork.org> * * This file is part of org.appwork.utils.locale * * This software is licensed under the Artistic License 2.0, * see the LICENSE file or http://www.opensource.org/licenses/artistic-license-2.0.php * for details */ package org.appwork.utils.locale; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Locale; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import org.appwork.storage.JSonStorage; import org.appwork.storage.Storage; import org.appwork.utils.Application; import org.appwork.utils.logging.Log; /** * This class provides functions to return translated strings * * @author Christian */ @Deprecated public class Loc { /** * The directory, where all localization files are located. A_ because this * the order is important. */ // public static final File A_LOCALIZATION_DIR = // Application.getResource("languages/"); public static final Storage CFG = JSonStorage.getStorage("Locale"); /** * The HashMap which contains all hashcodes of the keys and their translated * values. * * @see Loc#parseLocalization(RFSFile) */ private static HashMap<Integer, String> DATA = null; private static String DEFAULT_LOCALE_CACHE; /** * The name of the default localization file. This is the english language. */ private static final String FALLBACK_LOCALE = "en_GB"; private static String locale; /** * The key (String) under which the saved localization-name is stored. */ public static final String PROPERTY_LOCALE = "PROPERTY_LOCALE2"; public static String _(final Translate t) { return t.s(); } public static String _(final Translate t, final Object... parameter) { return t.s(parameter); } /** * @return */ private static String getDefaultLocale() { if (Loc.DEFAULT_LOCALE_CACHE != null) { return Loc.DEFAULT_LOCALE_CACHE; } final String sys = System.getProperty("user.language").toLowerCase(); final String cou = System.getProperty("user.country").toUpperCase(); final String[] locs = Loc.getLocales(); if (locs.length == 0) { Loc.DEFAULT_LOCALE_CACHE = Loc.FALLBACK_LOCALE; } if (Loc.DEFAULT_LOCALE_CACHE == null) { for (final String l : locs) { if (l.equals(sys + "_" + cou)) { Loc.DEFAULT_LOCALE_CACHE = l; break; } } } if (Loc.DEFAULT_LOCALE_CACHE == null) { for (final String l : locs) { if (l.equals(sys)) { Loc.DEFAULT_LOCALE_CACHE = l; break; } } } if (Loc.DEFAULT_LOCALE_CACHE == null) { for (final String l : locs) { if (l.startsWith(sys + "_")) { Loc.DEFAULT_LOCALE_CACHE = l; break; } } } if (Loc.DEFAULT_LOCALE_CACHE == null) { for (final String l : locs) { if (l.equals(Loc.FALLBACK_LOCALE)) { Loc.DEFAULT_LOCALE_CACHE = l; break; } } } if (Loc.DEFAULT_LOCALE_CACHE == null) { Loc.DEFAULT_LOCALE_CACHE = locs[0]; } return Loc.DEFAULT_LOCALE_CACHE; } /** * Returns a localized regular expression for words that usualy ar present * in an error message * * @return */ public static String getErrorRegex() { return Loc.L("system.error", ".*(error|failed).*"); } /** * @return */ public static String getLocale() { return Loc.locale; } /** * @return */ public static String[] getLocales() { final ArrayList<String> ret = new ArrayList<String>(); // first look out for all translations in filesystem String[] files; files = Application.getResource("languages/").list(new FilenameFilter() { public boolean accept(final File dir, final String name) { return name.endsWith(".loc"); } }); if (files != null) { for (final String file : files) { ret.add(file.substring(0, file.length() - 4)); } } // Search in jar: try { URL url = Application.getRessourceURL("languages/"); if (url != null) { Enumeration<URL> resources; resources = Thread.currentThread().getContextClassLoader().getResources("languages/"); while (resources.hasMoreElements()) { url = resources.nextElement(); if (url.getProtocol().equalsIgnoreCase("jar")) { final String path = url.getPath(); final int index = path.lastIndexOf('!'); final String jarPath = path.substring(0, index); final String internPath = path.substring(index + 2); final JarInputStream jarFile = new JarInputStream(new FileInputStream(new File(new URL(jarPath).toURI()))); JarEntry e; String jarName; while ((e = jarFile.getNextJarEntry()) != null) { jarName = e.getName(); if (jarName.startsWith(internPath) && jarName.endsWith(".loc")) { String filename = new File(jarName).getName(); filename = filename.substring(0, filename.length() - 4); ret.remove(filename); ret.add(filename); } } } else { files = new File(url.toURI()).list(new FilenameFilter() { public boolean accept(final File dir, final String name) { return name.endsWith(".loc"); } }); if (files != null) { for (final String file : files) { ret.add(file.substring(0, file.length() - 4)); } } } } } } catch (final Exception e) { Log.exception(e); } return ret.toArray(new String[] {}); } public static URL getResourceURL(final String loc) throws MalformedURLException { final File singleFile = Application.getResource("languages/" + loc + ".loc"); URL file = Application.getRessourceURL("languages/" + loc + ".loc"); if (singleFile.exists() && singleFile.length() > 0 || file == null) { file = singleFile.toURI().toURL(); } return file; } /** * Returns the translated value for the translation-key. If the current * language file doesn't contain the translated value, the default value * will be returned. * * @param key * key for the translation in the language file. the key should * <b>always</b> have the following structure * <i>PACKAGE_NAME_FROM_CALLER.CLASS_NAME_FROM_CALLER.key</i> * @param def * default value which will be returned if there is no mapping * for the key * @return translated value or the def parameter * @see Loc#LF(String, String, Object...) * @throws IllegalArgumentException * if the key is null or is empty */ public static String L(String key, final String def) { if (key == null || (key = key.trim()).length() == 0) { throw new IllegalArgumentException(); } if (Loc.DATA == null) { Log.L.warning("No parsed localization found! Loading now from saved localization file!"); try { Loc.setLocale(Loc.CFG.get(Loc.PROPERTY_LOCALE, Loc.FALLBACK_LOCALE)); } catch (final Exception e) { Log.L.severe("Error while loading the stored localization name!"); Loc.setLocale(Loc.FALLBACK_LOCALE); } if (Loc.DATA == null) { return def == null ? "Error in Loc! No loaded data!" : def; } } final String loc = Loc.DATA.get(key.toLowerCase().hashCode()); if (loc == null) { Loc.DATA.put(key.toLowerCase().hashCode(), def); return def; } return loc; } /** * Returns the translated value for the translation-key filled with the * parameters. * * @param key * key for the translation in the language file. the key should * <b>always</b> have the following structure * <i>PACKAGE_NAME_FROM_CALLER.CLASS_NAME_FROM_CALLER.key</i> * @param def * default value which will be returned if there is no mapping * for the key * @param args * parameters which should be inserted in the translated string * @return translated value or the def parameter filled with the parameters * @see Loc#L(String, String) */ public static String LF(final String key, final String def, final Object... args) { try { return String.format(Loc.L(key, def), args); } catch (final Exception e) { return "Error: " + key; } } /** * Creates a HashMap with the data obtained from the localization file. <br> * <b>Warning:</b> Overwrites any previously created HashMap * * @param file * {@link RFSFile} object to the localization file * @throws IllegalArgumentException * if the parameter is null or doesn't exist * @see Loc#DATA */ public static void parseLocalization(final URL file) throws IllegalArgumentException { if (file == null) { throw new IllegalArgumentException(); } if (Loc.DATA != null) { Log.L.finer("Previous HashMap will be overwritten!"); } Loc.DATA = new HashMap<Integer, String>(); BufferedReader reader = null; InputStreamReader isr = null; InputStream fis = null; try { reader = new BufferedReader(isr = new InputStreamReader(fis = file.openStream(), "UTF8")); String line; String key; String value; int split; while ((line = reader.readLine()) != null) { if (line.startsWith("#")) { continue; } if ((split = line.indexOf('=')) <= 0) { continue; } key = line.substring(0, split).toLowerCase().trim(); value = line.substring(split + 1).trim(); value = value.replace("\\n", "\n").replace("\\r", "\r"); Loc.DATA.put(key.hashCode(), value); } } catch (final FileNotFoundException e) { throw new IllegalArgumentException(e); } catch (final Exception e) { org.appwork.utils.logging.Log.exception(e); } finally { try { reader.close(); } catch (final Throwable e) { } try { isr.close(); } catch (final Throwable e) { } try { fis.close(); } catch (final Throwable e) { } } } /** * Set-up this class by creating the HashMap for the key-string-pairs. * * @param loc * name of the localization file * @see Loc#parseLocalization(RFSFile) */ public static void setLocale(String loc) { try { if (loc == null) { loc = Loc.CFG.get(Loc.PROPERTY_LOCALE, Loc.getDefaultLocale()); } // first check filesystem final URL file = Loc.getResourceURL(loc); Loc.locale = loc; if (file != null) { // TODO final String[] locs = loc.split("_"); if (locs.length == 1) { Locale.setDefault(new Locale(locs[0])); } else { Locale.setDefault(new Locale(locs[0], locs[1])); } Loc.CFG.put(Loc.PROPERTY_LOCALE, loc); Loc.parseLocalization(file); } else { Log.L.info("The language " + loc + " isn't available! Parsing default (" + Loc.FALLBACK_LOCALE + ".loc) one!"); Loc.locale = Loc.getDefaultLocale(); final String[] locs = Loc.locale.split("_"); Locale.setDefault(new Locale(locs[0], locs[1])); Loc.parseLocalization(Loc.getResourceURL(Loc.FALLBACK_LOCALE)); } } catch (final Exception e) { org.appwork.utils.logging.Log.exception(e); } } }