Index: AbstractFunction.java
===================================================================
--- AbstractFunction.java	(revision 44005)
+++ AbstractFunction.java	(revision 44006)
@@ -1,10 +1,15 @@
 package org.gvsig.expressionevaluator.spi;
 
+import java.io.InputStream;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Objects;
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.Range;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.math.util.MathUtils;
 import org.gvsig.expressionevaluator.Code;
 import org.gvsig.expressionevaluator.Code.Caller.Arguments;
@@ -12,14 +17,17 @@
 import org.gvsig.expressionevaluator.Interpreter;
 import org.gvsig.fmap.geom.Geometry;
 import org.gvsig.fmap.geom.primitive.Point;
+import org.json.JSONArray;
+import org.json.JSONObject;
 
+@SuppressWarnings("UseSpecificCatch")
 public abstract class AbstractFunction implements Function {
  
     private final String name;
-    private final String group;
-    private final Range argc;
-    private final String description;
-    private final String[] descriptionArgs;
+    private String group;
+    private Range argc;
+    private String description;
+    private String[] descriptionArgs;
     private List<String> alias;
     private String template;
     private String returnType;
@@ -34,6 +42,7 @@
         this.descriptionArgs = descriptionArgs;
         this.returnType = returnType;
         this.sqlCompatible = sqlCompatible;
+        load_from_resource();
     }
     protected AbstractFunction(String group, String name, Range argc, String description, String template, String[] descriptionArgs, String returnType) {
         this(group, name, argc, description, template, descriptionArgs, returnType, false);
@@ -83,9 +92,15 @@
 
     @Override
     public void addAlias(String name) {
+        if( StringUtils.isBlank(name) ) {
+            return;
+        }
         if( this.alias == null ) {
             this.alias = new ArrayList<>();
         }
+        if( this.alias.contains(name) ) {
+            return;
+        }
         this.alias.add(name);
     }
 
@@ -226,4 +241,75 @@
         }
         return BooleanUtils.toBoolean(value.toString());
     } 
+
+    private void load_from_resource() {
+        String lang = Locale.getDefault().getLanguage();
+        URL url = this.getClass().getResource("/org/gvsig/expressionevaluator/functions/"+lang+"/"+this.name()+".json");
+        if( url == null ) {
+            url = this.getClass().getResource("/org/gvsig/expressionevaluator/functions/en/"+this.name()+".json");
+            if( url == null ) {
+                return;
+            }
+        }
+        InputStream is = null;
+        JSONObject json;
+        try {
+            is = url.openStream();
+            List<String> lines = IOUtils.readLines(is);
+            json = new JSONObject(StringUtils.join(lines,  "\n"));
+        } catch (Exception ex) {
+            return;
+        } finally {
+            IOUtils.closeQuietly(is);
+        }
+        
+        if( json.has("group") ) {
+            this.group = json.getString("group");
+        }
+        if( json.has("description") ) {
+            Object x = json.get("description");
+            if( x instanceof String ) {
+                this.description = (String) x;
+            } else if( x instanceof JSONArray ) {
+                StringBuilder builder = new StringBuilder();
+                for (int i = 0; i < ((JSONArray)x).length(); i++) {
+                    if( i>0 ) {
+                        builder.append(" ");
+                    }
+                    builder.append(((JSONArray)x).getString(i));
+                }
+                this.description = builder.toString();
+            } else {
+                this.description = x.toString();
+            }
+            this.description = StringUtils.replace(
+                    this.description, 
+                    "@@@", 
+                    url.toString()
+            );
+        }
+        if( json.has("template") ) {
+            this.template = json.getString("template");
+        }
+        if( json.has("returnType") ) {
+            this.returnType = json.getString("returnType");
+        }
+        if( json.has("sqlCompatible") ) {
+            this.sqlCompatible = json.getBoolean("sqlCompatible");
+        }
+        if( json.has("args") ) {
+            JSONArray x = json.getJSONArray("args");
+            String[] args = new String[x.length()];
+            for (int i = 0; i < x.length(); i++) {
+                args[i] = x.getString(i);
+            }
+            this.descriptionArgs = args;
+        }
+        if( json.has("alias") ) {
+            JSONArray x = json.getJSONArray("alias");
+            for (int i = 0; i < x.length(); i++) {
+                this.addAlias(x.getString(i));
+            }
+        }
+    }
 }
