Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryTrafficSignLayer.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryTrafficSignLayer.java	(revision 32065)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryTrafficSignLayer.java	(revision 32066)
@@ -23,5 +23,4 @@
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.plugins.mapillary.traffico.TrafficoSign;
-import org.openstreetmap.josm.plugins.mapillary.traffico.TrafficoSignElement;
 import org.openstreetmap.josm.tools.I18n;
 
@@ -38,5 +37,5 @@
       throw new IOException(I18n.tr("Traffic sign font at ''{0}'' has wrong format.", TRAFFICO_PATH), e);
     } catch (IOException e) {
-      throw new IOException(I18n.tr("Could not read font-file from ''{{0}}''.", TRAFFICO_PATH), e);
+      throw new IOException(I18n.tr("Could not read font-file from ''{0}''.", TRAFFICO_PATH), e);
     }
   }
@@ -81,5 +80,5 @@
     points[2] = mv.getPoint(new LatLon(49.01038, 8.40636));
 
-    TrafficoSignElement[][] signs = {
+    TrafficoSign[] signs = {
         TrafficoSign.getSign("europe", "mandatory_cycle_track"),
         TrafficoSign.getSign("de", "information_bus_stop"),
@@ -87,7 +86,7 @@
 
     for (int i = 0; i < signs.length && i < points.length; i++) {
-      for (TrafficoSignElement layer : signs[i]) { // TODO: NPE
-        g.setColor(layer.getColor());
-        g.drawString(Character.toString(layer.getGlyph()), points[i].x - 25, points[i].y + 25);
+      for (int j = 0; signs[i] != null && j < signs[i].getNumElements(); j++) {
+        g.setColor(signs[i].getElement(j).getColor());
+        g.drawString(Character.toString(signs[i].getElement(j).getGlyph()), points[i].x - 25, points[i].y + 25);
       }
     }
@@ -100,8 +99,5 @@
         if (!((MapillaryImage) img).getSigns().isEmpty()) {
           Point imgLoc = mv.getPoint(img.getLatLon());
-          for (TrafficoSignElement e : TrafficoSign.getSign("de", ((MapillaryImage) img).getSigns().get(0))) {
-            g.setColor(e.getColor());
-            g.drawString(Character.toString(e.getGlyph()), imgLoc.x, imgLoc.y);
-          }
+          // TODO: Paint a sign from the image
         }
       }
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/traffico/TrafficoSign.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/traffico/TrafficoSign.java	(revision 32065)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/traffico/TrafficoSign.java	(revision 32066)
@@ -6,8 +6,8 @@
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
 
 import javax.json.Json;
@@ -17,75 +17,166 @@
 import org.openstreetmap.josm.Main;
 
+/**
+ * <p>
+ * Representation of a traffico sign, which consists of a country code, a unique name and the individual
+ * layers of the sign.
+ * </p><p>
+ * You can obtain a {@link TrafficoSign} via {@link #getSign(String, String)}. The first call to that method reads
+ * all sign definition for the queried country from disk and holds them in memory for future access.
+ * </p><p>
+ * You can rely on the fact, that two instances of {@link TrafficoSign} with same {@link #getName()} and same
+ * {@link #getCountry()} that were obtained via {@link #getSign(String, String)} will return <code>true</code> when
+ * compared with <code>==</code>
+ * </p>
+ */
 public final class TrafficoSign {
-  private static Map<String, Map<String, TrafficoSignElement[]>> signs = new HashMap<>();
+  private static final String SIGN_DEFINITION_PATH = "/data/fonts/traffico/signs/%s.json";
+  /**
+   * The signs that are already created from the JSON source file
+   */
+  private static final Map<String, Map<String, TrafficoSign>> signs = new TreeMap<>();
 
-  private TrafficoSign() {
-    // private constructor to avoid instantiation
+  private final String country;
+  private final String name;
+  private final TrafficoSignElement[] elements;
+
+  private TrafficoSign(TrafficoSignElement[] elements, String country, String name) {
+    this.country = country;
+    this.name = name;
+    if (elements == null) {
+      this.elements = new TrafficoSignElement[0];
+    } else {
+      this.elements = elements.clone();
+    }
   }
 
-  public static TrafficoSignElement[] getSign(String country, String signName) {
-    if (signs.get(country) == null) {
-      Main.info("Reading signs for country ''{0}''.", country);
-      try (
-        InputStream countryStream = TrafficoSign.class
-            .getResourceAsStream("/data/fonts/traffico/signs/" + country + ".json")) {
-        if (countryStream == null) {
-          return null;
-        }
-        JsonObject countrySigns = Json.createReader(countryStream).readObject();
-        Set<String> countrySignNames = countrySigns.keySet();
-        Main.info(
-            countrySignNames.size() + " different signs are supported for ''{0}'' by the Mapillary-plugin .",
-            country
+  /**
+   * @return the country of this sign
+   */
+  public String getCountry() {
+    return country;
+  }
+
+  /**
+   * @return the name of the sign
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * @return the number of sign elements (=layers) of which this sign consists
+   */
+  public int getNumElements() {
+    return elements.length;
+  }
+
+  /**
+   *
+   * @param index the index which is assigned to the sign element in question
+   * @return the sign element (=layer) with the given index
+   * @throws ArrayIndexOutOfBoundsException if index >= {@link #getNumElements()} or index < 0
+   */
+  public TrafficoSignElement getElement(int index) {
+    return elements[index];
+  }
+
+  /**
+   * <p>
+   * Returns the sign associated with the given country and name or <code>null</code> if no such sign is available.
+   * </p><p>
+   * If you obtain two instances of {@link TrafficoSign} with this method that have the same country and name, you can
+   * safely assume that a comparison of both objects with <code>==</code> will result in <code>true</code>.
+   * </p>
+   * @param country the country to which the sign belongs
+   * @param signName the name of the sign (unique in a country)
+   * @return the requested sign or <code>null</code> if this sign is unavailable
+   */
+  public static TrafficoSign getSign(String country, String signName) {
+    synchronized (signs) {
+      if (!signs.containsKey(country)) {
+        buildSignsFromJsonDefinition(country);
+      }
+      if (signs.containsKey(country) && signs.get(country).containsKey(signName)) {
+        return signs.get(country).get(signName);
+      }
+      return null;
+    }
+  }
+
+  private static void addSign(TrafficoSign sign) {
+    synchronized (signs) {
+      // Create Map for country if not already exists
+      if (!signs.containsKey(sign.getCountry())) {
+        signs.put(sign.getCountry(), new TreeMap<String, TrafficoSign>());
+      }
+      // Don't overwrite existing sign with same country-name-combination
+      if (signs.get(sign.getCountry()).containsKey(sign.getName())) {
+        Main.warn(
+            "The sign {0}--{1} was found multiple times in the traffico sign-definitions.",
+            sign.getName(), sign.getCountry()
         );
-        Map<String, TrafficoSignElement[]> countryMap = new HashMap<>();
-        for (String name : countrySignNames) {
-          JsonArray elements = countrySigns.getJsonObject(name).getJsonArray("elements");
-
-          // TODO: Replace by an array when all types of sign elements (text!) are
-          // supported
-          List<TrafficoSignElement> layers = new ArrayList<>();
-
-          for (int i = 0; i < elements.size(); i++) {
-            Character glyph = TrafficoGlyph.getGlyph(elements.getJsonObject(i)
-                .getString("type"));
-            if (glyph != null) {
-              Color c;
-              switch (elements.getJsonObject(i).getString("color").toLowerCase()) {
-                case "black":
-                  c = Color.BLACK;
-                  break;
-                case "red":
-                  c = Color.RED;
-                  break;
-                case "blue":
-                  c = Color.BLUE;
-                  break;
-                case "white":
-                  c = Color.WHITE;
-                  break;
-                case "green":
-                  c = Color.GREEN;
-                  break;
-                case "yellow":
-                  c = Color.YELLOW;
-                  break;
-                default:
-                  c = Color.MAGENTA;
-              }
-              layers.add(new TrafficoSignElement(glyph, c));
-            }
-          }
-          countryMap.put(name, layers.toArray(new TrafficoSignElement[layers.size()]));
-        }
-        signs.put(country, countryMap);
-      } catch (IOException e) {
-        Main.error(e);
+      } else {
+        signs.get(sign.getCountry()).put(sign.getName(), sign);
       }
     }
-    if (signs.get(country).get(signName) != null) {
-      return signs.get(country).get(signName);
+  }
+
+  private static void buildSignsFromJsonDefinition(String country) {
+    Main.info("Reading signs for country ''{0}''.", country);
+    try (
+      InputStream countryStream = TrafficoSign.class.getResourceAsStream(String.format(SIGN_DEFINITION_PATH, country))
+    ) {
+      if (countryStream == null) {
+        return;
+      }
+      JsonObject countrySigns = Json.createReader(countryStream).readObject();
+      Set<String> countrySignNames = countrySigns.keySet();
+      Main.info(
+          countrySignNames.size() + " different signs are supported for ''{0}'' by the Mapillary-plugin .",
+          country
+      );
+
+      // TODO: Replace by an array when all types of sign elements (text!) are supported
+      List<TrafficoSignElement> signLayers = new ArrayList<>();
+      for (String name : countrySignNames) {
+        signLayers.clear();
+        JsonArray elements = countrySigns.getJsonObject(name).getJsonArray("elements");
+
+        for (int i = 0; i < elements.size(); i++) {
+          Character glyph = TrafficoGlyph.getGlyph(elements.getJsonObject(i).getString("type"));
+          if (glyph != null) {
+            Color c;
+            switch (elements.getJsonObject(i).getString("color").toLowerCase()) {
+              case "black":
+                c = Color.BLACK;
+                break;
+              case "red":
+                c = new Color(0xc1121c);
+                break;
+              case "blue":
+                c = new Color(0x154889);
+                break;
+              case "white":
+                c = Color.WHITE;
+                break;
+              case "green":
+                c = new Color(0x008754);
+                break;
+              case "yellow":
+                c = new Color(0xfecf33);
+                break;
+              default:
+                c = Color.MAGENTA;
+                break;
+            }
+            signLayers.add(new TrafficoSignElement(glyph, c));
+          }
+        }
+        addSign(new TrafficoSign(signLayers.toArray(new TrafficoSignElement[signLayers.size()]), country, name));
+      }
+    } catch (IOException e) {
+      Main.error(e);
     }
-    return null;
   }
 }
