Index: trunk/build.xml
===================================================================
--- trunk/build.xml	(revision 2753)
+++ trunk/build.xml	(revision 2754)
@@ -98,8 +98,6 @@
 			<zipfileset dir="images" prefix="images" />
 			<zipfileset dir="data" prefix="data" />
-			<zipfileset src="lib/josm-translation.jar" />
 
 			<!-- All jar files necessary to run only JOSM (no tests) -->
-			<zipfileset src="lib/gettext-commons-0.9.6.jar" />
 			<zipfileset src="lib/metadata-extractor-2.3.1-nosun.jar" />
 			<zipfileset src="lib/commons-codec-1.4.jar" />
Index: trunk/src/org/openstreetmap/josm/gui/preferences/LanguagePreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/LanguagePreference.java	(revision 2753)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/LanguagePreference.java	(revision 2754)
@@ -5,11 +5,8 @@
 
 import java.awt.Component;
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
-import java.util.logging.Logger;
 
 import javax.swing.Box;
@@ -21,18 +18,10 @@
 import javax.swing.JPanel;
 import javax.swing.ListCellRenderer;
-import javax.swing.SwingUtilities;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.PleaseWaitRunnable;
-import org.openstreetmap.josm.io.OsmTransferException;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.I18n;
-import org.xml.sax.SAXException;
 
 public class LanguagePreference implements PreferenceSetting {
-    static private final Logger logger = Logger.getLogger(LanguagePreference.class.getName());
-
     public static class Factory implements PreferenceSettingFactory {
         public PreferenceSetting createPreferenceSetting() {
@@ -52,4 +41,5 @@
         langCombo = new JComboBox(model);
         langCombo.setRenderer(new LanguageCellRenderer(langCombo.getRenderer()));
+        model.selectLanguage(Main.pref.get("language"));
 
         LafPreference lafPreference = gui.getSetting(LafPreference.class);
@@ -59,19 +49,4 @@
         panel.add(langCombo, GBC.eol().fill(GBC.HORIZONTAL));
         panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
-
-        // this defers loading of available translations to the first time the tab
-        // with the available translations is selected by the user
-        //
-        gui.displaycontent.addChangeListener(
-                new ChangeListener() {
-                    public void stateChanged(ChangeEvent e) {
-                        int i = gui.displaycontent.getSelectedIndex();
-                        String title = gui.displaycontent.getTitleAt(i);
-                        if (title.equals(tr("Look and Feel"))) {
-                            initiallyLoadAvailableTranslations();
-                        }
-                    }
-                }
-        );
     }
 
@@ -87,73 +62,10 @@
     }
 
-    /**
-     * Load available translations if not loaded yet.
-     */
-    public void initiallyLoadAvailableTranslations() {
-        if (!translationsLoaded) {
-            reloadAvailableTranslations();
-        }
-        translationsLoaded = true;
-    }
-
-    /**
-     * Asynchronously loads available translations
-     *
-     */
-    protected void reloadAvailableTranslations() {
-        Main.worker.submit(new AvailableTranslationsLoader());
-    }
-
-    /**
-     * Asynchronous task to lookup the available translations.
-     *
-     */
-    private class AvailableTranslationsLoader extends PleaseWaitRunnable {
-        public AvailableTranslationsLoader() {
-            super(tr("Looking up available translations..."));
-        }
-
-        @Override
-        protected void cancel() {
-            // can't cancel
-        }
-
-        @Override
-        protected void realRun() throws SAXException, IOException, OsmTransferException {
-            final List<Locale> locales = new ArrayList<Locale>(
-                    Arrays.asList(I18n.getAvailableTranslations(getProgressMonitor()))
-            );
-            locales.add(0,Locale.ENGLISH);
-            Runnable r = new Runnable() {
-                public void run() {
-                    model.setAvailableLocales(locales);
-                    model.selectLanguage(Main.pref.get("language"));
-                }
-            };
-            try {
-                SwingUtilities.invokeAndWait(r);
-            } catch(InvocationTargetException e) {
-                throw new RuntimeException(e.getCause());
-            } catch(InterruptedException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        @Override
-        protected void finish() {}
-    }
-
     private static class LanguageComboBoxModel extends DefaultComboBoxModel {
         private final List<Locale> data = new ArrayList<Locale>();
 
-        public LanguageComboBoxModel() {}
-
-        public void setAvailableLocales(List<Locale> locales) {
-            data.clear();
-            if (locales != null) {
-                data.add(null); // the default locale
-                data.addAll(locales);
-            }
-            fireContentsChanged(this, 0, getSize());
+        public LanguageComboBoxModel(){
+            data.add(0,null);
+            data.addAll(Arrays.asList(I18n.getAvailableTranslations()));
         }
 
Index: trunk/src/org/openstreetmap/josm/tools/I18n.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/I18n.java	(revision 2753)
+++ trunk/src/org/openstreetmap/josm/tools/I18n.java	(revision 2754)
@@ -2,16 +2,18 @@
 package org.openstreetmap.josm.tools;
 
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.net.URL;
 import java.text.MessageFormat;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import java.util.Vector;
-import java.util.logging.Logger;
-
-import org.openstreetmap.josm.gui.MainApplication;
+
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.xnap.commons.i18n.I18nFactory;
 
 /**
@@ -21,8 +23,10 @@
  */
 public class I18n {
-    static private final Logger logger = Logger.getLogger(I18n.class.getName());
-
-    /* Base name for translation data. Used for detecting available translations */
-    private static final String TR_BASE = "org.openstreetmap.josm.i18n.Translation_";
+    private enum PluralMode { MODE_NOTONE, MODE_NONE, MODE_GREATERONE,
+    MODE_CS, MODE_AR, MODE_PL, MODE_RO, MODE_RU, MODE_SK, MODE_SL}
+    private static PluralMode pluralMode = PluralMode.MODE_NOTONE; /* english default */
+    private static HashMap<String, String> strings = null;
+    private static HashMap<String, String[]> pstrings = null;
+    private static HashMap<String, PluralMode> languages = new HashMap<String, PluralMode>();
 
     /**
@@ -30,22 +34,14 @@
      * many strings are already loaded.
      */
-    public static org.xnap.commons.i18n.I18n i18n;
-
     public static final String tr(String text, Object... objects) {
-        if (i18n == null)
-            return MessageFormat.format(filter(text), objects);
-        return filter(i18n.tr(text, objects));
+        return MessageFormat.format(gettext(text, null), objects);
     }
 
     public static final String tr(String text) {
-        if (i18n == null)
-            return filter(text);
-        return filter(i18n.tr(text));
+        return gettext(text, null);
     }
 
     public static final String trc(String ctx, String text) {
-        if (i18n == null)
-            return text;
-        return i18n.trc(ctx, text);
+        return gettext(text, ctx);
     }
 
@@ -60,33 +56,53 @@
 
     public static final String trn(String text, String pluralText, long n, Object... objects) {
-        if (i18n == null)
-            return n == 1 ? tr(text, objects) : tr(pluralText, objects);
-            return filter(i18n.trn(text, pluralText, n, objects));
+        return MessageFormat.format(gettextn(text, pluralText, null, n), objects);
     }
 
     public static final String trn(String text, String pluralText, long n) {
-        if (i18n == null)
-            return n == 1 ? tr(text) : tr(pluralText);
-            return filter(i18n.trn(text, pluralText, n));
+        return gettextn(text, pluralText, null, n);
     }
 
     public static final String trnc(String ctx, String text, String pluralText, long n, Object... objects) {
-        if (i18n == null)
-            return n == 1 ? tr(text, objects) : tr(pluralText, objects);
-            return i18n.trnc(ctx, text, pluralText, n, objects);
+        return MessageFormat.format(gettextn(text, pluralText, ctx, n), objects);
     }
 
     public static final String trnc(String ctx, String text, String pluralText, long n) {
-        if (i18n == null)
-            return n == 1 ? tr(text) : tr(pluralText);
-            return i18n.trnc(ctx, text, pluralText, n);
-    }
-
-    public static final String filter(String text)
+        return gettextn(text, pluralText, ctx, n);
+    }
+
+    public static final String gettext(String text, String ctx)
     {
         int i;
-        if(text.startsWith("_:") && (i = text.indexOf("\n")) >= 0)
-            return text.substring(i+1);
+        if(ctx == null && text.startsWith("_:") && (i = text.indexOf("\n")) >= 0)
+        {
+            ctx = text.substring(2,i-1);
+            text = text.substring(i+1);
+        }
+        if(strings != null)
+        {
+            String trans = strings.get(ctx == null ? text : "_:"+ctx+"\n"+text);
+            if(trans != null)
+                return trans;
+        }
         return text;
+    }
+
+    public static final String gettextn(String text, String plural, String ctx, long num)
+    {
+        int i;
+        if(ctx == null && text.startsWith("_:") && (i = text.indexOf("\n")) >= 0)
+        {
+            ctx = text.substring(2,i-1);
+            text = text.substring(i+1);
+        }
+        if(pstrings != null)
+        {
+            i = pluralEval(num);
+            String[] trans = pstrings.get(ctx == null ? text : "_:"+ctx+"\n"+text);
+            if(trans != null && trans.length >= i)
+                return trans[i];
+        }
+
+        return num == 1 ? text : plural;
     }
 
@@ -95,35 +111,16 @@
      * @return an array of locale objects.
      */
-    public static final Locale[] getAvailableTranslations(ProgressMonitor monitor) {
-        monitor.indeterminateSubTask(tr("Loading available locales..."));
+    public static final Locale[] getAvailableTranslations() {
         Vector<Locale> v = new Vector<Locale>();
-        LinkedList<String>str = new LinkedList<String>();
-        Locale[] l = Locale.getAvailableLocales();
-        monitor.subTask(tr("Checking locales..."));
-        monitor.setTicksCount(l.length);
-        for (int i = 0; i < l.length; i++) {
-            monitor.setCustomText(tr("Checking translation for locale ''{0}''", l[i].getDisplayName()));
-            String loc = l[i].toString();
-            String cn = TR_BASE + loc;
-            try {
-                Class.forName(cn);
-                v.add(l[i]);
-                str.add(loc);
-            } catch (ClassNotFoundException e) {
-            }
-            monitor.worked(1);
-        }
-        /* hmm, don't know why this is necessary */
-        try {
-            if(!str.contains("nb")) {
-                v.add(new Locale("nb"));
-            }
-        } catch (Exception e) {}
-        try {
-            if(!str.contains("gl")) {
-                v.add(new Locale("gl"));
-            }
-        } catch (Exception e) {}
-        l = new Locale[v.size()];
+        if(Main.class.getResource("/data/en.lang") != null)
+        {
+            for (String loc : languages.keySet()) {
+                if(Main.class.getResource("/data/"+loc+".lang") != null) {
+                    v.add(new Locale(loc));
+                }
+            }
+        }
+        v.add(Locale.ENGLISH);
+        Locale[] l = new Locale[v.size()];
         l = v.toArray(l);
         Arrays.sort(l, new Comparator<Locale>() {
@@ -137,7 +134,180 @@
     public static void init()
     {
+        languages.put("ar", PluralMode.MODE_AR);
+        languages.put("bg", PluralMode.MODE_NOTONE);
+        languages.put("cs", PluralMode.MODE_CS);
+        languages.put("da", PluralMode.MODE_NOTONE);
+        languages.put("de", PluralMode.MODE_NOTONE);
+        languages.put("el", PluralMode.MODE_NOTONE);
+        languages.put("en_GB", PluralMode.MODE_NOTONE);
+        languages.put("es", PluralMode.MODE_NOTONE);
+        languages.put("et", PluralMode.MODE_NOTONE);
+        languages.put("fi", PluralMode.MODE_NOTONE);
+        languages.put("fr", PluralMode.MODE_GREATERONE);
+        languages.put("gl", PluralMode.MODE_NOTONE);
+        languages.put("is", PluralMode.MODE_NOTONE);
+        languages.put("it", PluralMode.MODE_NOTONE);
+        languages.put("iw_IL", PluralMode.MODE_NOTONE);
+        languages.put("ja", PluralMode.MODE_NONE);
+        languages.put("nb", PluralMode.MODE_NOTONE);
+        languages.put("nl", PluralMode.MODE_NOTONE);
+        languages.put("pl", PluralMode.MODE_PL);
+        languages.put("pt_BR", PluralMode.MODE_GREATERONE);
+        languages.put("ro", PluralMode.MODE_RO);
+        languages.put("ru", PluralMode.MODE_RU);
+        languages.put("sk", PluralMode.MODE_SK);
+        languages.put("sl", PluralMode.MODE_SL);
+        languages.put("sv", PluralMode.MODE_NOTONE);
+        languages.put("tr", PluralMode.MODE_NONE);
+        languages.put("zh_TW", PluralMode.MODE_NONE);
+
         /* try initial language settings, may be changed later again */
-        try { i18n = I18nFactory.getI18n(MainApplication.class); }
-        catch (MissingResourceException ex) { Locale.setDefault(Locale.ENGLISH);}
+        if(!load(Locale.getDefault().toString()))
+            Locale.setDefault(Locale.ENGLISH);
+    }
+
+    public static boolean load(String l)
+    {
+        if(l.equals("en"))
+        {
+          strings = null;
+          pstrings = null;
+          pluralMode = PluralMode.MODE_NOTONE;
+          return true;
+        }
+        URL en = Main.class.getResource("/data/en.lang");
+        if(en == null)
+            return false;
+        URL tr = Main.class.getResource("/data/"+l+".lang");
+        if(tr == null)
+        {
+            int i = l.indexOf('_');
+            if (i > 0)
+                l = l.substring(0, i);
+            tr = Main.class.getResource("/data/"+l+".lang");
+            if(tr == null)
+                return false;
+        }
+
+        HashMap<String, String> s = new HashMap<String, String>();
+        HashMap<String, String[]> p = new HashMap<String, String[]>();
+        /* file format:
+           for all single strings:
+           {
+             unsigned short (2 byte) stringlength
+             string
+           }
+           unsigned short (2 byte) 0xFFFF (marks end of single strings)
+           for all multi strings:
+           {
+             unsigned char (1 byte) stringcount
+             for stringcount
+               unsigned short (2 byte) stringlength
+               string
+           }
+        */
+        try
+        {
+            InputStream ens = new BufferedInputStream(en.openStream());
+            InputStream trs = new BufferedInputStream(tr.openStream());
+            if(ens == null || trs == null)
+                return false;
+            byte[] enlen = new byte[2];
+            byte[] trlen = new byte[2];
+            boolean multimode = false;
+            byte[] str = new byte[4096];
+            for(;;)
+            {
+                if(multimode)
+                {
+                    int ennum = ens.read();
+                    int trnum = trs.read();
+                    if((ennum == -1 && trnum != -1) || (ennum != -1 && trnum == -1)) /* files do not match */
+                        return false;
+                    if(ennum == -1) /* EOF */
+                        break;
+                    String[] enstrings = new String[ennum];
+                    String[] trstrings = new String[trnum];
+                    for(int i = 0; i < ennum; ++i)
+                    {
+                        int val = ens.read(enlen);
+                        if(val != 2) /* file corrupt */
+                            return false;
+                        val = (enlen[0] < 0 ? 256+enlen[0]:enlen[0])*256+(enlen[1] < 0 ? 256+enlen[1]:enlen[1]);
+                        if(val > str.length)
+                            str = new byte[val];
+                        int rval = ens.read(str, 0, val);
+                        if(rval != val) /* file corrupt */
+                            return false;
+                        enstrings[i] = new String(str, 0, val, "utf-8");
+                    }
+                    for(int i = 0; i < trnum; ++i)
+                    {
+                        int val = trs.read(trlen);
+                        if(val != 2) /* file corrupt */
+                            return false;
+                        val = (trlen[0] < 0 ? 256+trlen[0]:trlen[0])*256+(trlen[1] < 0 ? 256+trlen[1]:trlen[1]);
+                        if(val > str.length)
+                            str = new byte[val];
+                        int rval = trs.read(str, 0, val);
+                        if(rval != val) /* file corrupt */
+                            return false;
+                        trstrings[i] = new String(str, 0, val, "utf-8");
+                    }
+                    if(trnum > 0)
+                        p.put(enstrings[0], trstrings);
+                }
+                else
+                {
+                    int enval = ens.read(enlen);
+                    int trval = trs.read(trlen);
+                    if(enval != trval) /* files do not match */
+                        return false;
+                    if(enval == -1) /* EOF */
+                        break;
+                    if(enval != 2) /* files corrupt */
+                        return false;
+                    enval = (enlen[0] < 0 ? 256+enlen[0]:enlen[0])*256+(enlen[1] < 0 ? 256+enlen[1]:enlen[1]);
+                    trval = (trlen[0] < 0 ? 256+trlen[0]:trlen[0])*256+(trlen[1] < 0 ? 256+trlen[1]:trlen[1]);
+                    if(enval == 0xFFFF)
+                    {
+                        multimode = true;
+                        if(trval != 0xFFFF) /* files do not match */
+                            return false;
+                    }
+                    else
+                    {
+                        if(enval > str.length)
+                            str = new byte[enval];
+                        if(trval > str.length)
+                            str = new byte[trval];
+                        int val = ens.read(str, 0, enval);
+                        if(val != enval) /* file corrupt */
+                            return false;
+                        String enstr = new String(str, 0, enval, "utf-8");
+                        if(trval != 0)
+                        {
+                            val = trs.read(str, 0, trval);
+                            if(val != trval) /* file corrupt */
+                                return false;
+                            String trstr = new String(str, 0, trval, "utf-8");
+                            s.put(enstr, trstr);
+                        }
+                    }
+                }
+            }
+        }
+        catch(Exception e)
+        {
+            return false;
+        }
+        if(!s.isEmpty())
+        {
+            strings = s;
+            pstrings = p;
+            pluralMode = languages.get(l);
+            return true;
+        }
+        return false;
     }
 
@@ -154,5 +324,4 @@
         if (localeName != null) {
             Locale l;
-            Locale d = Locale.getDefault();
             if (localeName.equals("he")) {
                 localeName = "iw_IL";
@@ -164,17 +333,48 @@
                 l = new Locale(localeName);
             }
-            try {
+            if(load(localeName)) {
                 Locale.setDefault(l);
-                i18n = I18nFactory.getI18n(MainApplication.class);
-            } catch (MissingResourceException ex) {
+            } else {
                 if (!l.getLanguage().equals("en")) {
                     System.out.println(tr("Unable to find translation for the locale {0}. Reverting to {1}.",
-                            l.getDisplayName(), d.getDisplayName()));
-                    Locale.setDefault(d);
+                            l.getDisplayName(), Locale.getDefault().getDisplayName()));
                 } else {
-                    i18n = null;
+                    strings = null;
+                    pstrings = null;
                 }
             }
         }
     }
+
+    private static int pluralEval(long n)
+    {
+        switch(pluralMode)
+        {
+        case MODE_NOTONE: /* bg, da, de, el, en, en_GB, es, et, fi, gl, is, it, iw_IL, nb, nl, sv */
+            return ((n != 1) ? 1 : 0);
+        case MODE_NONE: /* ja, tr, zh_TW */
+            return 0;
+        case MODE_GREATERONE: /* fr, pt_BR */
+            return ((n > 1) ? 1 : 0);
+        case MODE_CS:
+            return ((n == 1) ? 0 : (((n >= 2) && (n <= 4)) ? 1 : 2));
+        case MODE_AR:
+            return ((n == 0) ? 0 : ((n == 1) ? 1 : ((n == 2) ? 2 : ((((n % 100) >= 3)
+            && ((n % 100) <= 10)) ? 3 : ((((n % 100) >= 11) && ((n % 100) <= 99)) ? 4 : 5)))));
+        case MODE_PL:
+            return ((n == 1) ? 0 : (((((n % 10) >= 2) && ((n % 10) <= 4))
+            && (((n % 100) < 10) || ((n % 100) >= 20))) ? 1 : 2));
+        case MODE_RO:
+            return ((n == 1) ? 0 : ((((n % 100) > 19) || (((n % 100) == 0) && (n != 0))) ? 2 : 1));
+        case MODE_RU:
+            return ((((n % 10) == 1) && ((n % 100) != 11)) ? 0 : (((((n % 10) >= 2)
+            && ((n % 10) <= 4)) && (((n % 100) < 10) || ((n % 100) >= 20))) ? 1 : 2));
+        case MODE_SK:
+            return ((n == 1) ? 1 : (((n >= 2) && (n <= 4)) ? 2 : 0));
+        case MODE_SL:
+            return (((n % 100) == 1) ? 1 : (((n % 100) == 2) ? 2 : ((((n % 100) == 3)
+            || ((n % 100) == 4)) ? 3 : 0)));
+        }
+        return 0;
+    }
 }
