Index: main/kernel/src/org/ametys/runtime/config/ConfigManager.java
===================================================================
--- main/kernel/src/org/ametys/runtime/config/ConfigManager.java	(revision 33441)
+++ main/kernel/src/org/ametys/runtime/config/ConfigManager.java	(working copy)
@@ -26,6 +26,7 @@
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -55,6 +56,7 @@
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 
+import org.ametys.core.util.I18nUtils;
 import org.ametys.core.util.I18nizableText;
 import org.ametys.runtime.parameter.Enumerator;
 import org.ametys.runtime.parameter.Errors;
@@ -72,7 +74,7 @@
  */
 public final class ConfigManager implements Contextualizable, Serviceable, Initializable
 {
- // shared instance
+    // shared instance
     private static ConfigManager __manager;
 
     // the regular expression for ids
@@ -84,6 +86,7 @@
     // Avalon stuff
     private ServiceManager _manager;
     private Context _context;
+    private I18nUtils _i18nUtils;
 
     // Used parameters (Map<id, featureId>)
     private Map<String, String> _usedParamsName;
@@ -103,6 +106,9 @@
     // The parameters classified by categories and groups
     private Map<I18nizableText, ParameterCategory> _categorizedParameters;
     
+    // The parameters classified by categories sorted alphabetically and groups
+    private Map<I18nizableText, ParameterCategory> _sortedCategories;
+    
     // Determines if the extension point is initialized
     private boolean _isInitialized;
 
@@ -123,7 +129,7 @@
     {
         // empty constructor
     }
-
+    
     /**
      * Returns the shared instance of the <code>PluginManager</code>
      * @return the shared instance of the PluginManager
@@ -155,7 +161,7 @@
     
     @Override
     public void service(ServiceManager manager)
-    {
+    {   
         _manager = manager;
     }
     
@@ -167,6 +173,7 @@
         _params = new LinkedHashMap<>();
         _declaredParameterCheckers = new LinkedHashMap<>();
         _parameterCheckers = new LinkedHashMap<>();
+        _sortedCategories = new TreeMap<> ();
         
         _validatorManager = new ThreadSafeComponentManager<>();
         _validatorManager.enableLogging(new SLF4JLoggerAdapter(LoggerFactory.getLogger("runtime.plugin.threadsafecomponent")));
@@ -828,10 +835,14 @@
         
         return categories;
     }
-
+    
     private  void _saxConfiguration(ContentHandler contentHandler) throws SAXException, ProcessingException
     {
-        for (I18nizableText categoryKey : _categorizedParameters.keySet())
+        /* Sort categories alphabetically.
+         * We sort each time we sax the configuration in case the language changes */
+        _sortCategories();
+        
+        for (I18nizableText categoryKey : _sortedCategories.keySet())
         {
             AttributesImpl tabAttrs = new AttributesImpl();
             tabAttrs.addCDATAAttribute("role", "tabs");
@@ -925,6 +936,31 @@
         }
     }
     
+    private void _sortCategories()
+    {
+        TreeMap<I18nizableText, ParameterCategory> sortedCategories = new TreeMap<>(new I18nizableTextComparator(_getI8nUtils()));
+        sortedCategories.putAll(_categorizedParameters);
+
+        _sortedCategories = sortedCategories;
+    }
+
+    private I18nUtils _getI8nUtils()
+    {
+        if (_i18nUtils == null)
+        {
+            try
+            {
+                _i18nUtils = (I18nUtils) _manager.lookup(I18nUtils.ROLE);
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException("Unable to lookup the i18n utils component", e);
+            }
+        }
+        
+        return _i18nUtils;
+    }
+    
     private  void _saxValues(ContentHandler contentHandler) throws SAXException
     {
         // Get configuration parameters
@@ -1253,17 +1289,26 @@
         handler.endDocument();
     }
     
+    /**
+     * Sort I18nizableText with their translation
+     */
     class I18nizableTextComparator implements Comparator<I18nizableText>
     {
+        private I18nUtils _i18nUtil; // i18Util instead of i18nUtils to avoid "hiding" warning
+        
+        public I18nizableTextComparator(I18nUtils i18nUtils)
+        {
+            _i18nUtil = i18nUtils;
+        }
+        
         @Override
         public int compare(I18nizableText t1, I18nizableText t2)
         {
-            return t1.toString().compareTo(t2.toString());
+            return _i18nUtil.translate(t1).compareTo(_i18nUtil.translate(t2));
         }
     }
     
     /**
-     * 
      * Represents a category of parameters
      */
     class ParameterCategory
