Index: trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginCheckBox.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginCheckBox.java	(revision 14382)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginCheckBox.java	(revision 14384)
@@ -63,5 +63,5 @@
                 if (!p.equals(pi) && p.requires != null && ppModel.isSelectedPlugin(p.getName())) {
                     for (String s : p.getRequiredPlugins()) {
-                        if (s.equals(pi.getName())) {
+                        if (s.equals(pi.getName()) || s.equals(pi.provides)) {
                             otherPlugins.add(p.getName());
                             break;
Index: trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferencesModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferencesModel.java	(revision 14382)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferencesModel.java	(revision 14384)
@@ -237,7 +237,9 @@
      */
     public PluginInformation getPluginInformation(String name) {
-        for (PluginInformation pi: availablePlugins) {
-            if (pi.getName() != null && pi.getName().equals(name))
-                return pi;
+        if (name != null) {
+            for (PluginInformation pi: availablePlugins) {
+                if (name.equals(pi.getName()) || name.equals(pi.provides))
+                    return pi;
+            }
         }
         return null;
Index: trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java	(revision 14382)
+++ trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java	(revision 14384)
@@ -607,4 +607,11 @@
     }
 
+    private static void logWrongPlatform(String plugin, String pluginPlatform) {
+        Logging.warn(
+                tr("Plugin {0} must be run on a {1} platform.",
+                        plugin, pluginPlatform
+                ));
+    }
+
     private static void logJavaUpdateRequired(String plugin, int requiredVersion) {
         Logging.warn(
@@ -640,7 +647,14 @@
     public static boolean checkLoadPreconditions(Component parent, Collection<PluginInformation> plugins, PluginInformation plugin) {
 
+        // make sure the plugin is not meant for another platform
+        if (!plugin.isForCurrentPlatform()) {
+            // Just log a warning, this is unlikely to happen as we display only relevant plugins in HMI
+            logWrongPlatform(plugin.name, plugin.platform);
+            return false;
+        }
+
         // make sure the plugin is compatible with the current Java version
         if (plugin.localminjavaversion > Utils.getJavaVersion()) {
-            // Just log a warning until we switch to Java 11 so that openjfx plugin does not trigger a popup
+            // Just log a warning until we switch to Java 11 so that javafx plugin does not trigger a popup
             logJavaUpdateRequired(plugin.name, plugin.localminjavaversion);
             return false;
@@ -686,4 +700,7 @@
             for (PluginInformation pi: plugins) {
                 pluginNames.add(pi.name);
+                if (pi.provides != null) {
+                    pluginNames.add(pi.provides);
+                }
             }
             Set<String> missingPlugins = new HashSet<>();
Index: trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java	(revision 14382)
+++ trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java	(revision 14384)
@@ -31,4 +31,6 @@
 import org.openstreetmap.josm.tools.LanguageInfo;
 import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.Platform;
+import org.openstreetmap.josm.tools.PlatformManager;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -62,4 +64,8 @@
     /** The list of required plugins, separated by ';' (from locally available jar). */
     public String localrequires;
+    /** The plugin platform on which it is meant to run (windows, osx, unixoid). */
+    public String platform;
+    /** The virtual plugin provided by this plugin, if native for a given platform. */
+    public String provides;
     /** The plugin link (for documentation). */
     public String link;
@@ -169,4 +175,6 @@
         this.className = other.className;
         this.requires = other.requires;
+        this.provides = other.provides;
+        this.platform = other.platform;
         this.link = other.link;
         this.description = other.description;
@@ -216,4 +224,6 @@
         }
         link = s;
+        platform = attr.getValue("Plugin-Platform");
+        provides = attr.getValue("Plugin-Provides");
         requires = attr.getValue("Plugin-Requires");
         s = attr.getValue(lang+"Plugin-Description");
@@ -422,8 +432,13 @@
         Collection<String> locations = getPluginLocations();
 
+        String[] nameCandidates = new String[] {
+                pluginName,
+                pluginName + "-" + PlatformManager.getPlatform().getPlatform().name().toLowerCase(Locale.ENGLISH)};
         for (String s : locations) {
-            File pluginFile = new File(s, pluginName + ".jar");
-            if (pluginFile.exists()) {
-                return new PluginInformation(pluginFile);
+            for (String nameCandidate: nameCandidates) {
+                File pluginFile = new File(s, nameCandidate + ".jar");
+                if (pluginFile.exists()) {
+                    return new PluginInformation(pluginFile);
+                }
             }
         }
@@ -579,3 +594,17 @@
         }
     }
+
+    /**
+     * Determines if this plugin can be run on the current platform.
+     * @return {@code true} if this plugin can be run on the current platform
+     * @since 14384
+     */
+    public boolean isForCurrentPlatform() {
+        try {
+            return platform == null || PlatformManager.getPlatform().getPlatform() == Platform.valueOf(platform.toUpperCase(Locale.ENGLISH));
+        } catch (IllegalArgumentException e) {
+            Logging.warn(e);
+            return true;
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/plugins/ReadLocalPluginInformationTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/ReadLocalPluginInformationTask.java	(revision 14382)
+++ trunk/src/org/openstreetmap/josm/plugins/ReadLocalPluginInformationTask.java	(revision 14384)
@@ -190,4 +190,8 @@
     }
 
+    protected void filterIrrelevantPlugins() {
+        availablePlugins.entrySet().removeIf(e -> !e.getValue().isForCurrentPlatform());
+    }
+
     @Override
     protected void realRun() throws SAXException, IOException, OsmTransferException {
@@ -207,4 +211,5 @@
         if (canceled) return;
         filterOldPlugins();
+        filterIrrelevantPlugins();
         getProgressMonitor().worked(1);
     }
Index: trunk/src/org/openstreetmap/josm/plugins/ReadRemotePluginInformationTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/plugins/ReadRemotePluginInformationTask.java	(revision 14382)
+++ trunk/src/org/openstreetmap/josm/plugins/ReadRemotePluginInformationTask.java	(revision 14384)
@@ -25,4 +25,5 @@
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import javax.swing.JLabel;
@@ -283,4 +284,8 @@
     }
 
+    protected List<PluginInformation> filterIrrelevantPlugins(List<PluginInformation> plugins) {
+        return plugins.stream().filter(PluginInformation::isForCurrentPlatform).collect(Collectors.toList());
+    }
+
     /**
      * Parses the plugin list
@@ -294,5 +299,5 @@
             InputStream in = new ByteArrayInputStream(doc.getBytes(StandardCharsets.UTF_8));
             List<PluginInformation> pis = new PluginListParser().parse(in);
-            availablePlugins.addAll(filterDeprecatedPlugins(pis));
+            availablePlugins.addAll(filterIrrelevantPlugins(filterDeprecatedPlugins(pis)));
         } catch (PluginListParseException e) {
             Logging.error(tr("Failed to parse plugin list document from site ''{0}''. Skipping site. Exception was: {1}", site, e.toString()));
