Index: trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java	(revision 8282)
+++ trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java	(revision 8283)
@@ -18,4 +18,5 @@
 import java.util.concurrent.atomic.AtomicLong;
 
+import org.openstreetmap.josm.tools.LanguageInfo;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -694,34 +695,17 @@
 
     /**
-     * Replies the a localized name for this primitive given by the value of the tags (in this order)
-     * <ul>
-     *   <li>name:lang_COUNTRY_Variant  of the current locale</li>
-     *   <li>name:lang_COUNTRY of the current locale</li>
-     *   <li>name:lang of the current locale</li>
-     *   <li>name of the current locale</li>
-     * </ul>
-     *
-     * null, if no such tag exists
-     *
-     * @return the name of this primitive
+     * Replies a localized name for this primitive given by the value of the name tags
+     * accessed from very specific (language variant) to more generic (default name).
+     *
+     * @see LanguageInfo#getLanguageCodes()
+     * @return the name of this primitive, <code>null</code> if no name exists
      */
     @Override
     public String getLocalName() {
-        final Locale locale = Locale.getDefault();
-        String key = "name:" + locale.toString();
-        String val = get(key);
-        if (val != null)
-            return val;
-
-        final String language = locale.getLanguage();
-        key = "name:" + language + "_" + locale.getCountry();
-        val = get(key);
-        if (val != null)
-            return val;
-
-        key = "name:" + language;
-        val = get(key);
-        if (val != null)
-            return val;
+        for(String s : LanguageInfo.getLanguageCodes(null)) {
+            String val = get("name:" + s);
+            if (val != null)
+                return val;
+        }
 
         return getName();
Index: trunk/src/org/openstreetmap/josm/tools/I18n.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/I18n.java	(revision 8282)
+++ trunk/src/org/openstreetmap/josm/tools/I18n.java	(revision 8283)
@@ -83,4 +83,6 @@
     private static volatile PluralMode pluralMode = PluralMode.MODE_NOTONE; /* english default */
     private static volatile String loadedCode = "en";
+    /** store the original system locale for further use */
+    public static final Locale SystemLocale = Locale.getDefault();
 
     /* Localization keys for file chooser (and color chooser). */
@@ -494,11 +496,5 @@
         URL tr = getTranslationFile(l);
         if (tr == null || !languages.containsKey(l)) {
-            int i = l.indexOf('_');
-            if (i > 0) {
-                l = l.substring(0, i);
-            }
-            tr = getTranslationFile(l);
-            if (tr == null || !languages.containsKey(l))
-                return false;
+            return false;
         }
         try (
@@ -738,7 +734,7 @@
 
     /**
-     * Setup special font for Khmer script, as the default Java font do not display these characters.
+     * Setup special font for Khmer script, as the default Java fonts do not display these characters.
      *
-     * @since 8281
+     * @since 8282
      */
     public static void setupLanguageFonts() {
Index: trunk/src/org/openstreetmap/josm/tools/LanguageInfo.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/LanguageInfo.java	(revision 8282)
+++ trunk/src/org/openstreetmap/josm/tools/LanguageInfo.java	(revision 8283)
@@ -4,4 +4,6 @@
 import static org.openstreetmap.josm.tools.I18n.trc;
 
+import java.util.Collection;
+import java.util.LinkedList;
 import java.util.Locale;
 
@@ -86,4 +88,7 @@
      * to identify the locale of a localized resource, but in some cases it may use the
      * programmatic name for locales, as replied by {@link Locale#toString()}.
+     * 
+     * For unknown country codes and variants this functuion already does fallback to
+     * internally known translations.
      *
      * @param locale the locale. Replies "en" if null.
@@ -92,15 +97,14 @@
     public static String getJOSMLocaleCode(Locale locale) {
         if (locale == null) return "en";
-        String full = locale.toString();
-        if ("iw_IL".equals(full))
-            return "he";
-        else if ("in".equals(full))
-            return "id";
-        else if ("ca__valencia".equals(full))
-            return "ca@valencia";
-        else if (I18n.hasCode(full)) // catch all non-single codes
-            return full;
-
-        // return single code
+        for(String full : getLanguageCodes(locale)) {
+            if ("iw_IL".equals(full))
+                return "he";
+            else if ("in".equals(full))
+                return "id";
+            else if (I18n.hasCode(full)) // catch all non-single codes
+                return full;
+        }
+
+        // return single code as fallback
         return locale.getLanguage();
     }
@@ -154,12 +158,15 @@
      */
     public static Locale getLocale(String localeName) {
-        localeName = getJavaLocaleCode(localeName);
-        if ("ca__valencia".equals(localeName)) {
-            return new Locale("ca", "", "valencia");
-        }
+        int country = localeName.indexOf("_");
+        int variant = localeName.indexOf("@");
+        if (variant < 0 && country >= 0)
+            variant = localeName.indexOf("_", country+1);
         Locale l;
-        int i = localeName.indexOf('_');
-        if (i > 0) {
-            l = new Locale(localeName.substring(0, i), localeName.substring(i + 1));
+        if (variant > 0 && country > 0) {
+            l = new Locale(localeName.substring(0, country), localeName.substring(country+1, variant), localeName.substring(variant + 1));
+        } else if (variant > 0) {
+            l = new Locale(localeName.substring(0, variant), "", localeName.substring(variant + 1));
+        } else if (country > 0) {
+            l = new Locale(localeName.substring(0, country), localeName.substring(country + 1));
         } else {
             l = new Locale(localeName);
@@ -208,3 +215,37 @@
         return code+"_";
     }
+
+    /**
+     * Replies a list of language codes for local names. Prefixes range from very specific
+     * to more generic.
+     * <ul>
+     *   <li>lang_COUNTRY@variant  of the current locale</li>
+     *   <li>lang@variant  of the current locale</li>
+     *   <li>lang_COUNTRY of the current locale</li>
+     *   <li>lang of the current locale</li>
+     * </ul>
+     *
+     * @param locale the locale to use, <code>null</code> for default locale
+     * @since 8283
+     * @return list of codes
+     */
+    public static Collection<String> getLanguageCodes(Locale l) {
+        Collection<String> list = new LinkedList<String>();
+        if(l == null)
+            l = Locale.getDefault();
+        String lang = l.getLanguage();
+        String c = l.getCountry();
+        String v = l.getVariant();
+        if(c.isEmpty())
+            c = null;
+        if(v != null && !v.isEmpty()) {
+            if(c != null)
+                list.add(lang+"_"+c+"@"+v);
+            list.add(lang+"@"+v);
+        }
+        if(c != null)
+            list.add(lang+"_"+c);
+        list.add(lang);
+        return list;
+    }
 }
