Index: trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java	(revision 15875)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java	(revision 15876)
@@ -370,9 +370,11 @@
         destroyTaginfoNationalActions();
         if (!newSel.isEmpty()) {
-            for (Entry<String, String> e : Territories.getNationalTaginfoUrls(
-                    newSel.iterator().next().getBBox().getCenter()).entrySet()) {
-                taginfoNationalActions.add(new TaginfoAction(tagTable, editHelper::getDataKey, editHelper::getDataValues,
-                        membershipTable, x -> (IRelation<?>) membershipData.getValueAt(x, 0), e.getValue(), e.getKey()));
-            }
+            Territories.getRegionalTaginfoUrls(
+                    newSel.iterator().next().getBBox().getCenter()).values().stream().flatMap(List::stream).forEach(
+                taginfo -> taginfoNationalActions.add(new TaginfoAction(tagTable, editHelper::getDataKey, editHelper::getDataValues,
+                        membershipTable, x -> (IRelation<?>) membershipData.getValueAt(x, 0),
+                        taginfo.getUrl(), String.join("/", taginfo.getIsoCodes())
+                            + (taginfo.getSuffix() == null ? "" : " (" + taginfo.getSuffix() + ")")))
+            );
             taginfoNationalActions.stream().map(membershipMenu::add).forEach(membershipMenuTagInfoNatItems::add);
             taginfoNationalActions.stream().map(tagMenu::add).forEach(tagMenuTagInfoNatItems::add);
Index: trunk/src/org/openstreetmap/josm/tools/TaginfoRegionalInstance.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/TaginfoRegionalInstance.java	(revision 15876)
+++ trunk/src/org/openstreetmap/josm/tools/TaginfoRegionalInstance.java	(revision 15876)
@@ -0,0 +1,64 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.tools;
+
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Describes a regional Taginfo instance.
+ * @since 15876
+ */
+public class TaginfoRegionalInstance {
+
+    /** Instance URL */
+    private final String url;
+    /** Set of ISO3166 codes for the covered areas */
+    private final Set<String> isoCodes;
+    /** Optional suffix to distinguish them in UI */
+    private final String suffix;
+
+    /**
+     * Constructs a new {@code TaginfoRegionalInstance}.
+     * @param url Instance URL. Must not be null
+     * @param isoCodes Set of ISO3166 codes for the covered areas. Must not be null
+     */
+    public TaginfoRegionalInstance(String url, Set<String> isoCodes) {
+        this(url, isoCodes, null);
+    }
+
+    /**
+     * Constructs a new {@code TaginfoRegionalInstance}.
+     * @param url Instance URL. Must not be null
+     * @param isoCodes Set of ISO3166 codes for the covered areas. Must not be null
+     * @param suffix Optional suffix to distinguish them in UI. Can be null
+     */
+    public TaginfoRegionalInstance(String url, Set<String> isoCodes, String suffix) {
+        this.url = Objects.requireNonNull(url);
+        this.isoCodes = Objects.requireNonNull(isoCodes);
+        this.suffix = suffix;
+    }
+
+    /**
+     * Returns the instance URL.
+     * @return instance URL
+     */
+    public String getUrl() {
+        return url;
+    }
+
+    /**
+     * Returns the set of ISO3166 codes for the covered areas.
+     * @return set of ISO3166 codes for the covered areas
+     */
+    public Set<String> getIsoCodes() {
+        return isoCodes;
+    }
+
+    /**
+     * Returns the optional suffix to distinguish them in UI.
+     * @return optional suffix to distinguish them in UI. Can be null
+     */
+    public String getSuffix() {
+        return suffix;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/tools/Territories.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Territories.java	(revision 15875)
+++ trunk/src/org/openstreetmap/josm/tools/Territories.java	(revision 15876)
@@ -7,12 +7,24 @@
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Optional;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.stream.Collectors;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+import javax.json.stream.JsonParser;
+import javax.json.stream.JsonParser.Event;
 
 import org.openstreetmap.josm.data.coor.LatLon;
@@ -24,4 +36,5 @@
 import org.openstreetmap.josm.io.IllegalDataException;
 import org.openstreetmap.josm.io.OsmReader;
+import org.openstreetmap.josm.spi.preferences.Config;
 
 /**
@@ -35,4 +48,6 @@
     private static final String ISO3166_1 = "ISO3166-1:alpha2";
     private static final String ISO3166_2 = "ISO3166-2";
+    private static final String ISO3166_1_LC = ISO3166_1.toLowerCase(Locale.ENGLISH);
+    private static final String ISO3166_2_LC = ISO3166_2.toLowerCase(Locale.ENGLISH);
     private static final String TAGINFO = "taginfo";
 
@@ -40,5 +55,6 @@
 
     private static volatile Map<String, GeoPropertyIndex<Boolean>> iso3166Cache;
-    private static volatile Map<String, String> taginfoCache;
+    private static volatile Map<String, TaginfoRegionalInstance> taginfoCache;
+    private static volatile Map<String, TaginfoRegionalInstance> taginfoGeofabrikCache;
 
     private Territories() {
@@ -104,4 +120,9 @@
      */
     public static synchronized void initialize() {
+        initializeInternalData();
+        initializeExternalData();
+    }
+
+    private static void initializeInternalData() {
         iso3166Cache = new HashMap<>();
         taginfoCache = new TreeMap<>();
@@ -126,5 +147,5 @@
                         String taginfo = osm.get(TAGINFO);
                         if (taginfo != null) {
-                            taginfoCache.put(iso1, taginfo);
+                            taginfoCache.put(iso1, new TaginfoRegionalInstance(taginfo, Collections.singleton(iso1)));
                         }
                     }
@@ -139,12 +160,50 @@
     }
 
-    /**
-     * Returns a map of national taginfo instances for the given location.
+    private static void initializeExternalData() {
+        taginfoGeofabrikCache = new TreeMap<>();
+        try (CachedFile cf = new CachedFile(Config.getUrls().getJOSMWebsite() + "/remote/geofabrik-index-v1-nogeom.json");
+                InputStream is = cf.getInputStream();
+                JsonParser json = Json.createParser(is)) {
+            while (json.hasNext()) {
+                Event event = json.next();
+                if (event == Event.START_OBJECT) {
+                    for (JsonValue feature : json.getObject().getJsonArray("features")) {
+                        JsonObject props = feature.asJsonObject().getJsonObject("properties");
+                        if (props != null) {
+                            JsonObject urls = props.getJsonObject("urls");
+                            if (urls != null) {
+                                String taginfo = urls.getString(TAGINFO);
+                                if (taginfo != null) {
+                                    JsonArray iso1 = props.getJsonArray(ISO3166_1_LC);
+                                    JsonArray iso2 = props.getJsonArray(ISO3166_2_LC);
+                                    if (iso1 != null) {
+                                        readExternalTaginfo(taginfo, iso1);
+                                    } else if (iso2 != null) {
+                                        readExternalTaginfo(taginfo, iso2);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (IOException e) {
+            throw new JosmRuntimeException(e);
+        }
+    }
+
+    private static void readExternalTaginfo(String taginfo, JsonArray jsonCodes) {
+        Set<String> isoCodes = jsonCodes.getValuesAs(JsonString.class).stream().map(JsonString::getString).collect(Collectors.toSet());
+        isoCodes.forEach(s -> taginfoGeofabrikCache.put(s, new TaginfoRegionalInstance(taginfo, isoCodes, "Geofabrik")));
+    }
+
+    /**
+     * Returns a map of regional taginfo instances for the given location.
      * @param ll lat/lon where to look.
-     * @return a map of national taginfo instances for the given location (code / url)
-     * @since 15565
-     */
-    public static Map<String, String> getNationalTaginfoUrls(LatLon ll) {
-        Map<String, String> result = new TreeMap<>();
+     * @return a map of regional taginfo instances for the given location (code / url)
+     * @since 15876
+     */
+    public static Map<String, List<TaginfoRegionalInstance>> getRegionalTaginfoUrls(LatLon ll) {
+        Map<String, List<TaginfoRegionalInstance>> result = new TreeMap<>();
         if (iso3166Cache != null) {
             for (String code : iso3166Cache.entrySet().parallelStream().distinct()
@@ -152,7 +211,7 @@
                 .map(Entry<String, GeoPropertyIndex<Boolean>>::getKey)
                 .collect(Collectors.toSet())) {
-                String taginfo = taginfoCache.get(code);
-                if (taginfo != null) {
-                    result.put(code, taginfo);
+                for (Map<String, TaginfoRegionalInstance> cache : Arrays.asList(taginfoCache, taginfoGeofabrikCache)) {
+                    Optional.ofNullable(cache.get(code)).ifPresent(
+                            taginfo -> result.computeIfAbsent(code, c -> new ArrayList<>()).add(taginfo));
                 }
             }
