You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2015/12/24 02:05:32 UTC

[1/3] incubator-freemarker git commit: More helpful JavaDoc for some OutputFormat-related parts.

Repository: incubator-freemarker
Updated Branches:
  refs/heads/2.3-gae 2153e2309 -> f112ed6ce


More helpful JavaDoc for some OutputFormat-related parts.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/7051e55c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/7051e55c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/7051e55c

Branch: refs/heads/2.3-gae
Commit: 7051e55cfffe244a9ef537c62ec71d45c9d569ad
Parents: 2153e23
Author: ddekany <dd...@apache.org>
Authored: Tue Dec 22 22:17:39 2015 +0100
Committer: ddekany <dd...@apache.org>
Committed: Tue Dec 22 22:17:39 2015 +0100

----------------------------------------------------------------------
 src/main/java/freemarker/template/Configuration.java | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7051e55c/src/main/java/freemarker/template/Configuration.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/template/Configuration.java b/src/main/java/freemarker/template/Configuration.java
index 4fd347c..7226ef2 100644
--- a/src/main/java/freemarker/template/Configuration.java
+++ b/src/main/java/freemarker/template/Configuration.java
@@ -1800,11 +1800,15 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
     }
     
     /**
-     * Sets the (default) output format. Usually, you leave this on its default, which is
-     * {@link UndefinedOutputFormat#INSTANCE}, and then override it for individual templates based on their name (like
-     * based on their "file" extension) with {@link #setTemplateConfigurations(TemplateConfigurationFactory)}. This
-     * setting is also overridden by the standard file extensions; see them at
-     * {@link #setRecognizeStandardFileExtensions(boolean)}.
+     * Sets the default output format. Usually, you should leave this on its default, which is
+     * {@link UndefinedOutputFormat#INSTANCE}, and then use standard file extensions like "ftlh" (for HTML output) and
+     * ensure that {@link #setRecognizeStandardFileExtensions(boolean)} is {@code true} (see the description of standard
+     * file extensions there too). Where that approach doesn't fit, like you have no control over the file extensions,
+     * templates can be associated to output formats with patterns matching their name (their path) using
+     * {@link #setTemplateConfigurations(TemplateConfigurationFactory)}. Last not least, if all templates will have the
+     * same output format, you may use {@link #setOutputFormat(OutputFormat)} to set a value like
+     * {@link HTMLOutputFormat#INSTANCE}, {@link XMLOutputFormat#INSTANCE}, etc. Also note templates can specify their
+     * own output format like {@code <#ftl output_format="HTML">}, which overrides any configuration settings. 
      * 
      * <p>
      * The output format is mostly important because of auto-escaping (see {@link #setAutoEscapingPolicy(int)}), but


[2/3] incubator-freemarker git commit: New output formats were in the wrong source directory

Posted by dd...@apache.org.
New output formats were in the wrong source directory


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/bec1430b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/bec1430b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/bec1430b

Branch: refs/heads/2.3-gae
Commit: bec1430b44ec205f08c8045825c8a0b10a7f87ab
Parents: 7051e55
Author: ddekany <dd...@apache.org>
Authored: Thu Dec 24 01:56:07 2015 +0100
Committer: ddekany <dd...@apache.org>
Committed: Thu Dec 24 01:56:07 2015 +0100

----------------------------------------------------------------------
 .../java/freemarker/core/CSSOutputFormat.java   | 34 +++++++++++++++++++
 .../java/freemarker/core/JSONOutputFormat.java  | 34 +++++++++++++++++++
 .../freemarker/core/JavaScriptOutputFormat.java | 35 ++++++++++++++++++++
 .../java/freemarker/core/CSSOutputFormat.java   | 34 -------------------
 .../java/freemarker/core/JSONOutputFormat.java  | 34 -------------------
 .../freemarker/core/JavaScriptOutputFormat.java | 35 --------------------
 6 files changed, 103 insertions(+), 103 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bec1430b/src/main/java/freemarker/core/CSSOutputFormat.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/CSSOutputFormat.java b/src/main/java/freemarker/core/CSSOutputFormat.java
new file mode 100644
index 0000000..e60e1c5
--- /dev/null
+++ b/src/main/java/freemarker/core/CSSOutputFormat.java
@@ -0,0 +1,34 @@
+package freemarker.core;
+
+/**
+ * Represents the CSS output format (MIME type "text/css", name "CSS"). This format doesn't support escaping.
+ * 
+ * @since 2.3.24
+ */
+public class CSSOutputFormat extends OutputFormat {
+
+    /**
+     * The only instance (singleton) of this {@link OutputFormat}.
+     */
+    public static final CSSOutputFormat INSTANCE = new CSSOutputFormat();
+    
+    private CSSOutputFormat() {
+        // Only to decrease visibility
+    }
+    
+    @Override
+    public String getName() {
+        return "CSS";
+    }
+
+    @Override
+    public String getMimeType() {
+        return "text/css";
+    }
+
+    @Override
+    public boolean isOutputFormatMixingAllowed() {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bec1430b/src/main/java/freemarker/core/JSONOutputFormat.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/JSONOutputFormat.java b/src/main/java/freemarker/core/JSONOutputFormat.java
new file mode 100644
index 0000000..7b0d9fe
--- /dev/null
+++ b/src/main/java/freemarker/core/JSONOutputFormat.java
@@ -0,0 +1,34 @@
+package freemarker.core;
+
+/**
+ * Represents the JSON output format (MIME type "application/json", name "JSON"). This format doesn't support escaping.
+ * 
+ * @since 2.3.24
+ */
+public class JSONOutputFormat extends OutputFormat {
+
+    /**
+     * The only instance (singleton) of this {@link OutputFormat}.
+     */
+    public static final JSONOutputFormat INSTANCE = new JSONOutputFormat();
+    
+    private JSONOutputFormat() {
+        // Only to decrease visibility
+    }
+    
+    @Override
+    public String getName() {
+        return "JSON";
+    }
+
+    @Override
+    public String getMimeType() {
+        return "application/json";
+    }
+
+    @Override
+    public boolean isOutputFormatMixingAllowed() {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bec1430b/src/main/java/freemarker/core/JavaScriptOutputFormat.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/JavaScriptOutputFormat.java b/src/main/java/freemarker/core/JavaScriptOutputFormat.java
new file mode 100644
index 0000000..a6375af
--- /dev/null
+++ b/src/main/java/freemarker/core/JavaScriptOutputFormat.java
@@ -0,0 +1,35 @@
+package freemarker.core;
+
+/**
+ * Represents the JavaScript output format (MIME type "application/javascript", name "JavaScript"). This format doesn't
+ * support escaping.
+ * 
+ * @since 2.3.24
+ */
+public class JavaScriptOutputFormat extends OutputFormat {
+
+    /**
+     * The only instance (singleton) of this {@link OutputFormat}.
+     */
+    public static final JavaScriptOutputFormat INSTANCE = new JavaScriptOutputFormat();
+    
+    private JavaScriptOutputFormat() {
+        // Only to decrease visibility
+    }
+    
+    @Override
+    public String getName() {
+        return "JavaScript";
+    }
+
+    @Override
+    public String getMimeType() {
+        return "application/javascript";
+    }
+
+    @Override
+    public boolean isOutputFormatMixingAllowed() {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bec1430b/src/test/java/freemarker/core/CSSOutputFormat.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/CSSOutputFormat.java b/src/test/java/freemarker/core/CSSOutputFormat.java
deleted file mode 100644
index e60e1c5..0000000
--- a/src/test/java/freemarker/core/CSSOutputFormat.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package freemarker.core;
-
-/**
- * Represents the CSS output format (MIME type "text/css", name "CSS"). This format doesn't support escaping.
- * 
- * @since 2.3.24
- */
-public class CSSOutputFormat extends OutputFormat {
-
-    /**
-     * The only instance (singleton) of this {@link OutputFormat}.
-     */
-    public static final CSSOutputFormat INSTANCE = new CSSOutputFormat();
-    
-    private CSSOutputFormat() {
-        // Only to decrease visibility
-    }
-    
-    @Override
-    public String getName() {
-        return "CSS";
-    }
-
-    @Override
-    public String getMimeType() {
-        return "text/css";
-    }
-
-    @Override
-    public boolean isOutputFormatMixingAllowed() {
-        return false;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bec1430b/src/test/java/freemarker/core/JSONOutputFormat.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/JSONOutputFormat.java b/src/test/java/freemarker/core/JSONOutputFormat.java
deleted file mode 100644
index 7b0d9fe..0000000
--- a/src/test/java/freemarker/core/JSONOutputFormat.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package freemarker.core;
-
-/**
- * Represents the JSON output format (MIME type "application/json", name "JSON"). This format doesn't support escaping.
- * 
- * @since 2.3.24
- */
-public class JSONOutputFormat extends OutputFormat {
-
-    /**
-     * The only instance (singleton) of this {@link OutputFormat}.
-     */
-    public static final JSONOutputFormat INSTANCE = new JSONOutputFormat();
-    
-    private JSONOutputFormat() {
-        // Only to decrease visibility
-    }
-    
-    @Override
-    public String getName() {
-        return "JSON";
-    }
-
-    @Override
-    public String getMimeType() {
-        return "application/json";
-    }
-
-    @Override
-    public boolean isOutputFormatMixingAllowed() {
-        return false;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bec1430b/src/test/java/freemarker/core/JavaScriptOutputFormat.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/JavaScriptOutputFormat.java b/src/test/java/freemarker/core/JavaScriptOutputFormat.java
deleted file mode 100644
index a6375af..0000000
--- a/src/test/java/freemarker/core/JavaScriptOutputFormat.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package freemarker.core;
-
-/**
- * Represents the JavaScript output format (MIME type "application/javascript", name "JavaScript"). This format doesn't
- * support escaping.
- * 
- * @since 2.3.24
- */
-public class JavaScriptOutputFormat extends OutputFormat {
-
-    /**
-     * The only instance (singleton) of this {@link OutputFormat}.
-     */
-    public static final JavaScriptOutputFormat INSTANCE = new JavaScriptOutputFormat();
-    
-    private JavaScriptOutputFormat() {
-        // Only to decrease visibility
-    }
-    
-    @Override
-    public String getName() {
-        return "JavaScript";
-    }
-
-    @Override
-    public String getMimeType() {
-        return "application/javascript";
-    }
-
-    @Override
-    public boolean isOutputFormatMixingAllowed() {
-        return false;
-    }
-
-}


[3/3] incubator-freemarker git commit: Added custom formatter examples to the Manual. Fixed/updated JavaDoc and Manual number/date formatting related parts (mostly).

Posted by dd...@apache.org.
Added custom formatter examples to the Manual. Fixed/updated JavaDoc and Manual number/date formatting related parts (mostly).


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/f112ed6c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/f112ed6c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/f112ed6c

Branch: refs/heads/2.3-gae
Commit: f112ed6ceb84eec5ada63ded39e0efcc2ee546bb
Parents: bec1430
Author: ddekany <dd...@apache.org>
Authored: Thu Dec 24 02:05:11 2015 +0100
Committer: ddekany <dd...@apache.org>
Committed: Thu Dec 24 02:05:11 2015 +0100

----------------------------------------------------------------------
 src/main/java/freemarker/core/Configurable.java |   8 +-
 src/main/java/freemarker/core/Environment.java  |   4 +-
 .../core/TemplateDateFormatFactory.java         |   2 +-
 .../core/TemplateNumberFormatFactory.java       |   2 +-
 .../java/freemarker/template/Configuration.java |  16 +-
 src/manual/en_US/book.xml                       | 621 ++++++++++++++++++-
 .../core/BaseNTemplateNumberFormatFactory.java  |  21 +-
 .../EpochMillisTemplateDateFormatFactory.java   |  12 +-
 .../freemarker/manual/CustomFormatsExample.java |  73 +++
 .../UnitAwareTemplateNumberFormatFactory.java   |  62 ++
 .../manual/UnitAwareTemplateNumberModel.java    |  25 +
 .../manual/CustomFormatsExample-alias1.ftlh     |   4 +
 .../manual/CustomFormatsExample-alias1.ftlh.out |   4 +
 .../manual/CustomFormatsExample-alias2.ftlh     |   1 +
 .../manual/CustomFormatsExample-alias2.ftlh.out |   1 +
 .../manual/CustomFormatsExample-modelAware.ftlh |   2 +
 .../CustomFormatsExample-modelAware.ftlh.out    |   2 +
 17 files changed, 807 insertions(+), 53 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/main/java/freemarker/core/Configurable.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Configurable.java b/src/main/java/freemarker/core/Configurable.java
index 9c82428..adba746 100644
--- a/src/main/java/freemarker/core/Configurable.java
+++ b/src/main/java/freemarker/core/Configurable.java
@@ -722,9 +722,9 @@ public class Configurable {
      *   <li>{@code "computer"}: The number format used by FTL's {@code c} built-in (like in {@code someNumber?c}).</li>
      *   <li>{@link java.text.DecimalFormat} pattern (like {@code "0.##"}). This syntax has a FreeMarker-specific
      *       extension, so that you can specify options like the rounding mode and the symbols used in this string. For
-     *       example, {@code ",000;; rnd=hu grp=_"} will format numbers like {@code ",000"} would, but with half-up
-     *       rounding mode, and {@code _} as the group separator. See more about "extended Java decimal format" in the
-     *       FreeMarker Manual.
+     *       example, {@code ",000;; roundingMode=halfUp groupingSeparator=_"} will format numbers like {@code ",000"}
+     *       would, but with half-up rounding mode, and {@code _} as the group separator. See more about "extended Java
+     *       decimal format" in the FreeMarker Manual.
      *       </li>
      *   <li>If the string starts with {@code @} character followed by a letter then it's interpreted as a custom number
      *       format, but only if either {@link Configuration#getIncompatibleImprovements()} is at least 2.3.24, or
@@ -779,7 +779,7 @@ public class Configurable {
      * 
      * @param customNumberFormats
      *            Can't be {@code null}. The name must start with an UNICODE letter, and can only contain UNICODE
-     *            letters and digits.
+     *            letters and digits (not {@code _}).
      * 
      * @since 2.3.24
      */

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/main/java/freemarker/core/Environment.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Environment.java b/src/main/java/freemarker/core/Environment.java
index ef7a301..5ebf855 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -1501,7 +1501,7 @@ public final class Environment extends Configurable {
     
     /**
      * Gets a {@link TemplateDateFormat} for the specified parameters. This is mostly meant to be used by
-     * {@link TemplateDateFormatFactory} implementations to delegate to a format based on a specific format string. It's
+     * {@link TemplateDateFormatFactory} implementations to delegate to a format based on a specific format string. It
      * works well for that, as its parameters are the same low level values as the parameters of
      * {@link TemplateDateFormatFactory#get(String, int, Locale, TimeZone, boolean, Environment)}. For other tasks
      * consider the other overloads of this method.
@@ -1635,7 +1635,7 @@ public final class Environment extends Configurable {
     /**
      * Used to get the {@link TemplateDateFormat} according the date/time/datetime format settings, for the current
      * locale and time zone. See {@link #getTemplateDateFormat(String, int, Locale, TimeZone, boolean)} for the meaning
-     * of some if the parameters.
+     * of some of the parameters.
      */
     private TemplateDateFormat getTemplateDateFormat(int dateType, boolean useSQLDTTZ, boolean zonelessInput)
             throws TemplateValueFormatException {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/main/java/freemarker/core/TemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/TemplateDateFormatFactory.java b/src/main/java/freemarker/core/TemplateDateFormatFactory.java
index 23b88e0..9edda85 100644
--- a/src/main/java/freemarker/core/TemplateDateFormatFactory.java
+++ b/src/main/java/freemarker/core/TemplateDateFormatFactory.java
@@ -59,7 +59,7 @@ public abstract class TemplateDateFormatFactory extends TemplateValueFormatFacto
      *            The locale to format for. Not {@code null}. The resulting format should be bound to this locale
      *            forever (i.e. locale changes in the {@link Environment} must not be followed).
      * @param timeZone
-     *            The time zone to format for. Not {@code null}. The resulting format should be bound to this time zone
+     *            The time zone to format for. Not {@code null}. The resulting format must be bound to this time zone
      *            forever (i.e. time zone changes in the {@link Environment} must not be followed).
      * @param zonelessInput
      *            Indicates that the input Java {@link Date} is not from a time zone aware source. When this is

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/main/java/freemarker/core/TemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/TemplateNumberFormatFactory.java b/src/main/java/freemarker/core/TemplateNumberFormatFactory.java
index 9a404d3..e0d0bc6 100644
--- a/src/main/java/freemarker/core/TemplateNumberFormatFactory.java
+++ b/src/main/java/freemarker/core/TemplateNumberFormatFactory.java
@@ -48,7 +48,7 @@ public abstract class TemplateNumberFormatFactory extends TemplateValueFormatFac
      *            {@code "1, 2"} (and {@code "@fooBar"} selects the factory). The format of this string is up to the
      *            {@link TemplateNumberFormatFactory} implementation. Not {@code null}, often an empty string.
      * @param locale
-     *            The locale to format for. Not {@code null}. The resulting format should be bound to this locale
+     *            The locale to format for. Not {@code null}. The resulting format must be bound to this locale
      *            forever (i.e. locale changes in the {@link Environment} must not be followed).
      * @param env
      *            The runtime environment from which the formatting was called. This is mostly meant to be used for

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/main/java/freemarker/template/Configuration.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/template/Configuration.java b/src/main/java/freemarker/template/Configuration.java
index 7226ef2..a913cb7 100644
--- a/src/main/java/freemarker/template/Configuration.java
+++ b/src/main/java/freemarker/template/Configuration.java
@@ -1801,14 +1801,14 @@ public class Configuration extends Configurable implements Cloneable, ParserConf
     
     /**
      * Sets the default output format. Usually, you should leave this on its default, which is
-     * {@link UndefinedOutputFormat#INSTANCE}, and then use standard file extensions like "ftlh" (for HTML output) and
-     * ensure that {@link #setRecognizeStandardFileExtensions(boolean)} is {@code true} (see the description of standard
-     * file extensions there too). Where that approach doesn't fit, like you have no control over the file extensions,
-     * templates can be associated to output formats with patterns matching their name (their path) using
-     * {@link #setTemplateConfigurations(TemplateConfigurationFactory)}. Last not least, if all templates will have the
-     * same output format, you may use {@link #setOutputFormat(OutputFormat)} to set a value like
-     * {@link HTMLOutputFormat#INSTANCE}, {@link XMLOutputFormat#INSTANCE}, etc. Also note templates can specify their
-     * own output format like {@code <#ftl output_format="HTML">}, which overrides any configuration settings. 
+     * {@link UndefinedOutputFormat#INSTANCE}, and then use standard file extensions like "ftlh" (for HTML) or "ftlx"
+     * (for XML) and ensure that {@link #setRecognizeStandardFileExtensions(boolean)} is {@code true} (see more there).
+     * Where you can't use standard the file extensions, templates still can be associated to output formats with
+     * patterns matching their name (their path) using {@link #setTemplateConfigurations(TemplateConfigurationFactory)}.
+     * But if all templates will have the same output format, you may use {@link #setOutputFormat(OutputFormat)} after
+     * all, to set a value like {@link HTMLOutputFormat#INSTANCE}, {@link XMLOutputFormat#INSTANCE}, etc. Also note
+     * that templates can specify their own output format like {@code 
+     * <#ftl output_format="HTML">}, which overrides any configuration settings.
      * 
      * <p>
      * The output format is mostly important because of auto-escaping (see {@link #setAutoEscapingPolicy(int)}), but

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index b25ca0c..b68ff4c 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -4119,7 +4119,7 @@ ${("green " + "mouse")?upper_case}  &lt;#-- GREEN MOUSE --&gt;
           value will be converted to string according the default number
           format. This may includes the maximum number of decimals, grouping,
           and like. Usually the programmer should set the default number
-          format; the template author don't have to deal with it (but he can
+          format; the template author doesn't have to deal with it (but he can
           with the <literal>number_format</literal> setting; see in the <link
           linkend="ref_directive_setting">documentation of
           <literal>setting</literal> directive</link>). Also, you can override
@@ -4168,8 +4168,8 @@ ${("green " + "mouse")?upper_case}  &lt;#-- GREEN MOUSE --&gt;
 
           <para>If the expression evaluates to a date-like value then that
           will be transformed to a text according to a default format. Usually
-          the programmer should set the default format; you don't have to deal
-          with it (but if you care, <link
+          the programmer should set the default format; the template author
+          doesn't have to deal with it (but if you care, <link
           linkend="topic.dateTimeFormatSettings">see the
           <literal>date_format</literal>, <literal>time_format</literal> and
           <literal>datetime_format</literal> settings</link> in the
@@ -9163,30 +9163,594 @@ cfg.setTemplateConfigurations(
       <section xml:id="pgui_config_custom_formats">
         <title>Custom number and date/time formats</title>
 
-        <para>FreeMarker allows you to define your own number and
-        date/time/datetime formatter algorithms by implementing
-        <literal>freemarker.core.TemplateNumberFormatFactory</literal> and
-        <literal>freemarker.core.TemplateDateFormatFactory</literal>. These
-        formats can be registered with the
-        <literal>custom_number_formats</literal> and
-        <literal>custom_date_formats</literal> configuration settings. After
-        that, anywhere where you can specify formats with a
-        <literal>String</literal>, now you can refer to your custom format as
-        <literal>"@<replaceable>name</replaceable>"</literal>. So for example,
-        if you have registered your number format implementation with name
-        <literal>"smart"</literal>, then you could set the
-        <literal>number_format</literal> setting
-        (<literal>Configurable.setNumberFormat(String)</literal>) to
-        <literal>"@smart"</literal>, or issue
-        <literal>${n?string.@smart}</literal> or <literal>&lt;#setting
-        number_format="@smart"&gt;</literal> in a template.</para>
-
-        <para>[TODO] What other applications exist (aliasing, model-aware
-        formatters)</para>
-
-        <para>[TODO] Simple complete example</para>
-
-        <para>[TODO] Complex formatter example (base N with fallback)</para>
+        <section>
+          <title>Overview</title>
+
+          <para>FreeMarker allows you to define your own number and
+          date/time/datetime formats, and associate a name to them. This
+          mechanism has several applications:</para>
+
+          <itemizedlist>
+            <listitem>
+              <para>Custom formatter algorithms: You can use your own
+              formatter algorithm instead of relying on those provided by
+              FreeMarker. For this, implement
+              <literal>freemarker.core.TemplateNumberFormatFactory</literal>
+              or <literal>freemarker.core.TemplateDateFormatFactory</literal>.
+              You will find a few examples of this <link
+              linkend="pgui_config_custom_formats_ex_cust_alg_simple">below</link>.</para>
+            </listitem>
+
+            <listitem>
+              <para>Aliasing: You can give application-specific names (like
+              <quote>price</quote>, <quote>weight</quote>,
+              <quote>fileDate</quote>, <quote>logEventTime</quote>, etc.) to
+              other formats by using
+              <literal>AliasTemplateNumberFormatFactory</literal> and
+              <literal>AliasTemplateDateFormatFactory</literal>. Thus
+              templates can just refer to that name, like in
+              <literal>${lastModified?string.@fileDate}</literal>, instead of
+              specifying the format directly. Thus the formats can be
+              specified on a single central place (where you configure
+              FreeMarker), instead of being specified repeatedly in templates.
+              Also thus template authors don't have to enter complex and hard
+              to remember formatting patterns. <link
+              linkend="pgui_config_custom_formats_ex_alias">See example
+              below</link>.</para>
+            </listitem>
+
+            <listitem>
+              <para>Model-sensitive formatting: Applications can put custom
+              <literal>freemarker.TemplateModel</literal>-s into the
+              data-model instead of dropping plain values (like
+              <literal>int</literal>-s, <literal>double</literal>-s, etc.)
+              into it, to attach rendering-related information to the value.
+              Custom formatters can utilize this information (for example, to
+              show the unit after numbers), as they receive the
+              <literal>TemplateModel</literal> itself, not the wrapped raw
+              value. <link
+              linkend="pgui_config_custom_formats_ex_model_aware">See example
+              below</link>.</para>
+            </listitem>
+
+            <listitem>
+              <para>Format that prints markup instead of plain text: You might
+              want to use HTML tags (or other markup) in the formatted values,
+              such as coloring negative numbers to red or using HTML
+              <literal>sup</literal> element for exponents. This is possible
+              if you write a custom format as shown in previous cases, but
+              override the <literal>format</literal> method in the formatter
+              class so that it returns a
+              <literal>TemplateMarkupOutputModel</literal> instead of a
+              <literal>String</literal>. (You shouldn't just return the markup
+              as <literal>String</literal>, as then it might will be escaped;
+              see <link
+              linkend="dgui_misc_autoescaping">auto-escaping</link>.)</para>
+            </listitem>
+          </itemizedlist>
+
+          <para>Custom formats can be registered with the
+          <literal>custom_number_formats</literal> and
+          <literal>custom_date_formats</literal> configuration settings. After
+          that, anywhere where you can specify formats with a
+          <literal>String</literal>, now you can refer to your custom format
+          as <literal>"@<replaceable>name</replaceable>"</literal>. So for
+          example, if you have registered your number format implementation
+          with name <literal>"smart"</literal>, then you could set the
+          <literal>number_format</literal> setting
+          (<literal>Configurable.setNumberFormat(String)</literal>) to
+          <literal>"@smart"</literal>, or issue
+          <literal>${n?string.@smart}</literal> or <literal>&lt;#setting
+          number_format="@smart"&gt;</literal> in a template. Furthermore, you
+          can define parameters for your custom format, like <literal>"@smart
+          2"</literal>, and the interpretation of the parameters is up to your
+          formatter implementation.</para>
+        </section>
+
+        <section xml:id="pgui_config_custom_formats_ex_cust_alg_simple">
+          <title>Simple custom number format example</title>
+
+          <para>This custom number format shows numbers in hexadecimal
+          form:</para>
+
+          <programlisting role="unspecified">package com.example;
+
+import java.util.Locale;
+
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateNumberModel;
+import freemarker.template.utility.NumberUtil;
+
+public class HexTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
+
+    public static final HexTemplateNumberFormatFactory INSTANCE
+            = new HexTemplateNumberFormatFactory();
+    
+    private HexTemplateNumberFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateNumberFormat get(String params, Locale locale, Environment env)
+            throws InvalidFormatParametersException {
+        TemplateFormatUtil.checkHasNoParameters(params);
+        return HexTemplateNumberFormat.INSTANCE;
+    }
+
+    private static class HexTemplateNumberFormat extends TemplateNumberFormat {
+
+        private static final HexTemplateNumberFormat INSTANCE = new HexTemplateNumberFormat();
+        
+        private HexTemplateNumberFormat() { }
+        
+        @Override
+        public String formatToPlainText(TemplateNumberModel numberModel)
+                throws UnformattableValueException, TemplateModelException {
+            Number n = TemplateFormatUtil.getNonNullNumber(numberModel);
+            try {
+                return Integer.toHexString(NumberUtil.toIntExact(n));
+            } catch (ArithmeticException e) {
+                throw new UnformattableValueException(n + " doesn't fit into an int");
+            }
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public String getDescription() {
+            return "hexadecimal int";
+        }
+        
+    }
+
+}</programlisting>
+
+          <para>We register the above format with name
+          <quote>hex</quote>:</para>
+
+          <programlisting role="unspecified">// Where you initalize the application-wide Configuration singleton:
+Configuration cfg = ...;
+...
+Map&lt;String, TemplateNumberFormatFactory&gt; customNumberFormats = ...;
+...
+customNumberFormats.put("hex", HexTemplateNumberFormatFactory.INSTANCE);
+...
+cfg.setCustomNumberFormats(customNumberFormats);</programlisting>
+
+          <para>Now we can use this format in templates:</para>
+
+          <programlisting role="template">${x?string.@hex}</programlisting>
+
+          <para>or even set it as the default number format:</para>
+
+          <programlisting role="unspecified">cfg.setNumberFormat("@hex");</programlisting>
+        </section>
+
+        <section xml:id="pgui_config_custom_formats_ex_cust_algo_advanced">
+          <title>Advanced custom number format example</title>
+
+          <para>This is a more complex custom number format that shows how to
+          deal with parameters in the format string, also how to delegate to
+          another format:</para>
+
+          <programlisting role="unspecified">package com.example;
+
+import java.util.Locale;
+
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateNumberModel;
+import freemarker.template.utility.NumberUtil;
+import freemarker.template.utility.StringUtil;
+
+/**
+ * Shows a number in base N number system. Can only format numbers that fit into an {@code int},
+ * however, optionally you can specify a fallback format. This format has one required parameter,
+ * the numerical system base. That can be optionally followed by "|" and a fallback format.
+ */
+public class BaseNTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
+
+    public static final BaseNTemplateNumberFormatFactory INSTANCE
+            = new BaseNTemplateNumberFormatFactory();
+    
+    private BaseNTemplateNumberFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateNumberFormat get(String params, Locale locale, Environment env)
+            throws InvalidFormatParametersException {
+        TemplateNumberFormat fallbackFormat;
+        {
+            int barIdx = params.indexOf('|');
+            if (barIdx != -1) {
+                String fallbackFormatStr = params.substring(barIdx + 1);
+                params = params.substring(0, barIdx);
+                try {
+                    fallbackFormat = env.getTemplateNumberFormat(fallbackFormatStr, locale);
+                } catch (TemplateValueFormatException e) {
+                    throw new InvalidFormatParametersException(
+                            "Couldn't get the fallback number format (specified after the \"|\"), "
+                            + StringUtil.jQuote(fallbackFormatStr) + ". Reason: " + e.getMessage(),
+                            e);
+                }
+            } else {
+                fallbackFormat = null;
+            }
+        }
+        
+        int base;
+        try {
+            base = Integer.parseInt(params);
+        } catch (NumberFormatException e) {
+            if (params.length() == 0) {
+                throw new InvalidFormatParametersException(
+                        "A format parameter is required to specify the numerical system base.");
+            }
+            throw new InvalidFormatParametersException(
+                    "The format paramter must be an integer, but was (shown quoted): "
+                    + StringUtil.jQuote(params));
+        }
+        if (base &lt; 2) {
+            throw new InvalidFormatParametersException("A base must be at least 2.");
+        }
+        return new BaseNTemplateNumberFormat(base, fallbackFormat);
+    }
+
+    private static class BaseNTemplateNumberFormat extends TemplateNumberFormat {
+
+        private final int base;
+        private final TemplateNumberFormat fallbackFormat;
+        
+        private BaseNTemplateNumberFormat(int base, TemplateNumberFormat fallbackFormat) {
+            this.base = base;
+            this.fallbackFormat = fallbackFormat;
+        }
+        
+        @Override
+        public String formatToPlainText(TemplateNumberModel numberModel)
+                throws TemplateModelException, TemplateValueFormatException {
+            Number n = TemplateFormatUtil.getNonNullNumber(numberModel);
+            try {
+                return Integer.toString(NumberUtil.toIntExact(n), base);
+            } catch (ArithmeticException e) {
+                if (fallbackFormat == null) {
+                    throw new UnformattableValueException(
+                            n + " doesn't fit into an int, and there was no fallback format "
+                            + "specified.");
+                } else {
+                    return fallbackFormat.formatToPlainText(numberModel);
+                }
+            }
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public String getDescription() {
+            return "base " + base;
+        }
+        
+    }
+
+}</programlisting>
+
+          <para>We register the above format with name
+          <quote>base</quote>:</para>
+
+          <programlisting role="unspecified">// Where you initalize the application-wide Configuration singleton:
+Configuration cfg = ...;
+...
+Map&lt;String, TemplateNumberFormatFactory&gt; customNumberFormats = ...;
+...
+customNumberFormats.put("hex", BaseNTemplateNumberFormatFactory.INSTANCE);
+...
+cfg.setCustomNumberFormats(customNumberFormats);</programlisting>
+
+          <para>Now we can use this format in templates:</para>
+
+          <programlisting role="template">${x?string.@base_8}</programlisting>
+
+          <para>Above there the parameter string was <literal>"8"</literal>,
+          as FreeMarker allows separating that from the format name with
+          <literal>_</literal> instead of whitespace, so that you don't have
+          to write the longer
+          <literal><replaceable>n</replaceable>?string["@base 8"]</literal>
+          form.</para>
+
+          <para>Of course, we could also set this as the default number format
+          like:</para>
+
+          <programlisting role="unspecified">cfg.setNumberFormat("@base 8");</programlisting>
+
+          <para>Here's an example of using the a fallback number format (which
+          is <literal>"0.0###"</literal>):</para>
+
+          <programlisting role="unspecified">cfg.setNumberFormat("@base 8|0.0###");</programlisting>
+
+          <para>Note that this functionality, with the <literal>|</literal>
+          syntax and all, is purely implemented in the example code
+          earlier.</para>
+        </section>
+
+        <section xml:id="pgui_config_custom_formats_ex_cust_algo_date">
+          <title>Custom date/time format example</title>
+
+          <para>This simple date format formats the date/time value to the
+          milliseconds since the epoch:</para>
+
+          <programlisting role="unspecified">package com.example;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import freemarker.template.TemplateDateModel;
+import freemarker.template.TemplateModelException;
+
+public class EpochMillisTemplateDateFormatFactory extends TemplateDateFormatFactory {
+
+    public static final EpochMillisTemplateDateFormatFactory INSTANCE
+            = new EpochMillisTemplateDateFormatFactory();
+    
+    private EpochMillisTemplateDateFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateDateFormat get(String params, int dateType,
+            Locale locale, TimeZone timeZone, boolean zonelessInput,
+            Environment env)
+            throws InvalidFormatParametersException {
+        TemplateFormatUtil.checkHasNoParameters(params);
+        return EpochMillisTemplateDateFormat.INSTANCE;
+    }
+
+    private static class EpochMillisTemplateDateFormat extends TemplateDateFormat {
+
+        private static final EpochMillisTemplateDateFormat INSTANCE
+                = new EpochMillisTemplateDateFormat();
+        
+        private EpochMillisTemplateDateFormat() { }
+        
+        @Override
+        public String formatToPlainText(TemplateDateModel dateModel)
+                throws UnformattableValueException, TemplateModelException {
+            return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime());
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public boolean isTimeZoneBound() {
+            return false;
+        }
+
+        @Override
+        public Date parse(String s, int dateType) throws UnparsableValueException {
+            try {
+                return new Date(Long.parseLong(s));
+            } catch (NumberFormatException e) {
+                throw new UnparsableValueException("Malformed long");
+            }
+        }
+
+        @Override
+        public String getDescription() {
+            return "millis since the epoch";
+        }
+        
+    }
+
+}</programlisting>
+
+          <para>We register the above format with name
+          <quote>epoch</quote>:</para>
+
+          <programlisting role="unspecified">// Where you initalize the application-wide Configuration singleton:
+Configuration cfg = ...;
+...
+Map&lt;String, TemplateDateFormatFactory&gt; customDateFormats = ...;
+...
+customDateFormats.put("epoch", EpochMillisTemplateDateFormatFactory.INSTANCE);
+...
+cfg.setCustomDateFormats(customDateFormats);</programlisting>
+
+          <para>Now we can use this format in templates:</para>
+
+          <programlisting role="template">${t?string.@epoch}</programlisting>
+
+          <para>Of course, we could also set this as the default date-time
+          format like:</para>
+
+          <programlisting role="unspecified">cfg.setDateTimeFormat("@epoch");</programlisting>
+
+          <para>For a more complex that for example uses format parameters,
+          refer to the <link
+          linkend="pgui_config_custom_formats_ex_cust_algo_advanced">advanced
+          number format example</link>. Doing that with date formats is very
+          similar.</para>
+        </section>
+
+        <section xml:id="pgui_config_custom_formats_ex_alias">
+          <title>Alias format example</title>
+
+          <para>In this example we specify some number formats and date
+          formats that are aliases to another format:</para>
+
+          <programlisting role="unspecified">// Where you initalize the application-wide Configuration singleton:
+Configuration cfg = ...;
+
+Map&lt;String, TemplateNumberFormatFactory&gt; customNumberFormats
+        = new HashMap&lt;String, TemplateNumberFormatFactory&gt;();
+customNumberFormats.put("price", new AliasTemplateNumberFormatFactory(",000.00"));
+customNumberFormats.put("weight",
+        new AliasTemplateNumberFormatFactory("0.##;; roundingMode=halfUp"));
+cfg.setCustomNumberFormats(customNumberFormats);
+
+Map&lt;String, TemplateDateFormatFactory&gt; customDateFormats
+        = new HashMap&lt;String, TemplateDateFormatFactory&gt;();
+customDateFormats.put("fileDate", new AliasTemplateDateFormatFactory("dd/MMM/yy hh:mm a"));
+customDateFormats.put("logEventTime", new AliasTemplateDateFormatFactory("iso ms u"));
+cfg.setCustomDateFormats(customDateFormats);</programlisting>
+
+          <para>So now you can do this in a template:</para>
+
+          <programlisting role="template">${product.price?string.@price}
+${product.weight?string.@weight}
+${lastModified?string.@fileDate}
+${lastError.timestamp?string.@logEventTime}</programlisting>
+
+          <para>Note that the constructor parameter of
+          <literal>AliasTemplateNumberFormatFactory</literal> can naturally
+          refer to a custom format too:</para>
+
+          <programlisting role="unspecified">Map&lt;String, TemplateNumberFormatFactory&gt; customNumberFormats
+        = new HashMap&lt;String, TemplateNumberFormatFactory&gt;();
+customNumberFormats.put("base", BaseNTemplateNumberFormatFactory.INSTANCE);
+customNumberFormats.put("oct", new AliasTemplateNumberFormatFactory("@base 8"));
+cfg.setCustomNumberFormats(customNumberFormats);</programlisting>
+
+          <para>So now
+          <literal><replaceable>n</replaceable>?string.@oct</literal> will
+          format the number to octal form.</para>
+        </section>
+
+        <section xml:id="pgui_config_custom_formats_ex_model_aware">
+          <title>Model-aware format example</title>
+
+          <para>In this example we specify a number format that automatically
+          show the unit after the number if that was put into the data-model
+          as <literal>UnitAwareTemplateNumberModel</literal>. First let's see
+          <literal>UnitAwareTemplateNumberModel</literal>:</para>
+
+          <programlisting role="unspecified">package com.example;
+
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateNumberModel;
+
+public class UnitAwareTemplateNumberModel implements TemplateNumberModel {
+
+    private final Number value;
+    private final String unit;
+    
+    public UnitAwareTemplateNumberModel(Number value, String unit) {
+        this.value = value;
+        this.unit = unit;
+    }
+
+    @Override
+    public Number getAsNumber() throws TemplateModelException {
+        return value;
+    }
+
+    public String getUnit() {
+        return unit;
+    }
+
+}</programlisting>
+
+          <para>When you fill the data-model, you could do something like
+          this:</para>
+
+          <programlisting role="unspecified">Map&lt;String, Object&gt; dataModel = new HashMap&lt;&gt;();
+dataModel.put("weight", new UnitAwareTemplateNumberModel(1.5, "kg"));
+// Rather than just: dataModel.put("weight", 1.5);</programlisting>
+
+          <para>Then if we have this in the template:</para>
+
+          <programlisting role="template">${weight}</programlisting>
+
+          <para>we want to see this:</para>
+
+          <programlisting role="output">1.5 kg</programlisting>
+
+          <para>To achieve that, we define this custom number format:</para>
+
+          <programlisting role="unspecified">package com.example;
+
+import java.util.Locale;
+
+import freemarker.core.Environment;
+import freemarker.core.TemplateNumberFormat;
+import freemarker.core.TemplateNumberFormatFactory;
+import freemarker.core.TemplateValueFormatException;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateNumberModel;
+
+/**
+ * A number format that takes any other number format as parameter (specified as a string, as
+ * usual in FreeMarker), then if the model is a {@link UnitAwareTemplateNumberModel}, it  shows
+ * the unit after the number formatted with the other format, otherwise it just shows the formatted
+ * number without unit.
+ */
+public class UnitAwareTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
+
+    public static final UnitAwareTemplateNumberFormatFactory INSTANCE
+            = new UnitAwareTemplateNumberFormatFactory();
+
+    private UnitAwareTemplateNumberFormatFactory() {
+        // Defined to decrease visibility
+    }
+
+    @Override
+    public TemplateNumberFormat get(String params, Locale locale, Environment env)
+            throws TemplateValueFormatException {
+        return new UnitAwareNumberFormat(env.getTemplateNumberFormat(params, locale));
+    }
+
+    private static class UnitAwareNumberFormat extends TemplateNumberFormat {
+
+        private final TemplateNumberFormat innerFormat;
+
+        private UnitAwareNumberFormat(TemplateNumberFormat innerFormat) {
+            this.innerFormat = innerFormat;
+        }
+
+        @Override
+        public String formatToPlainText(TemplateNumberModel numberModel)
+                throws TemplateModelException, TemplateValueFormatException {
+            String innerResult = innerFormat.formatToPlainText(numberModel);
+            return numberModel instanceof UnitAwareTemplateNumberModel
+                    ? innerResult + " " + ((UnitAwareTemplateNumberModel) numberModel).getUnit()
+                    : innerResult;
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return innerFormat.isLocaleBound();
+        }
+
+        @Override
+        public String getDescription() {
+            return "unit-aware " + innerFormat.getDescription();
+        }
+
+    }
+
+}</programlisting>
+
+          <para>Finally, we set the above custom format as the default number
+          format:</para>
+
+          <programlisting role="unspecified">// Where you initalize the application-wide Configuration singleton:
+Configuration cfg = ...;
+
+Map&lt;String, TemplateNumberFormatFactory&gt; customNumberFormats = new HashMap&lt;&gt;();
+customNumberFormats.put("ua", UnitAwareTemplateNumberFormatFactory.INSTANCE);
+cfg.setCustomNumberFormats(customNumberFormats);
+
+// Note: "0.####;; roundingMode=halfUp" is a standard format specified in FreeMarker.
+cfg.setNumberFormat("@ua 0.####;; roundingMode=halfUp");</programlisting>
+        </section>
       </section>
 
       <section xml:id="pgui_config_incompatible_improvements">
@@ -15346,7 +15910,8 @@ Tue, Apr 8, '03
           </note>
 
           <para>To prevent misunderstandings, the format need not be a string
-          literal, it can be a variable or any other expression, like in
+          literal, it can be a variable or any other expression as far as it
+          evaluates to a string. For example, it can be like
           <literal>"<replaceable>...</replaceable>"?string[myFormat]</literal>.</para>
 
           <para>See also: <link

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/test/java/freemarker/core/BaseNTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/BaseNTemplateNumberFormatFactory.java b/src/test/java/freemarker/core/BaseNTemplateNumberFormatFactory.java
index 3639a38..a669bc8 100644
--- a/src/test/java/freemarker/core/BaseNTemplateNumberFormatFactory.java
+++ b/src/test/java/freemarker/core/BaseNTemplateNumberFormatFactory.java
@@ -25,9 +25,15 @@ import freemarker.template.TemplateNumberModel;
 import freemarker.template.utility.NumberUtil;
 import freemarker.template.utility.StringUtil;
 
+/**
+ * Shows a number in base N number system. Can only format numbers that fit into an {@code int},
+ * however, optionally you can specify a fallback format. This format has one required parameter,
+ * the numerical system base. That can be optionally followed by "|" and a fallback format.
+ */
 public class BaseNTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
 
-    public static final BaseNTemplateNumberFormatFactory INSTANCE = new BaseNTemplateNumberFormatFactory();
+    public static final BaseNTemplateNumberFormatFactory INSTANCE
+            = new BaseNTemplateNumberFormatFactory();
     
     private BaseNTemplateNumberFormatFactory() {
         // Defined to decrease visibility
@@ -61,10 +67,14 @@ public class BaseNTemplateNumberFormatFactory extends TemplateNumberFormatFactor
         } catch (NumberFormatException e) {
             if (params.length() == 0) {
                 throw new InvalidFormatParametersException(
-                        "A format parameter is required, which specifies the numerical system base.");
+                        "A format parameter is required to specify the numerical system base.");
             }
             throw new InvalidFormatParametersException(
-                    "The format paramter must be an integer, but was (shown quoted): " + StringUtil.jQuote(params));
+                    "The format paramter must be an integer, but was (shown quoted): "
+                    + StringUtil.jQuote(params));
+        }
+        if (base < 2) {
+            throw new InvalidFormatParametersException("A base must be at least 2.");
         }
         return new BaseNTemplateNumberFormat(base, fallbackFormat);
     }
@@ -88,7 +98,8 @@ public class BaseNTemplateNumberFormatFactory extends TemplateNumberFormatFactor
             } catch (ArithmeticException e) {
                 if (fallbackFormat == null) {
                     throw new UnformattableValueException(
-                            n + " doesn't fit into an int, and there was no fallback format specified.");
+                            n + " doesn't fit into an int, and there was no fallback format "
+                            + "specified.");
                 } else {
                     return fallbackFormat.formatToPlainText(numberModel);
                 }
@@ -102,7 +113,7 @@ public class BaseNTemplateNumberFormatFactory extends TemplateNumberFormatFactor
 
         @Override
         public String getDescription() {
-            return "hexadecimal int";
+            return "base " + base;
         }
         
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/test/java/freemarker/core/EpochMillisTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/EpochMillisTemplateDateFormatFactory.java b/src/test/java/freemarker/core/EpochMillisTemplateDateFormatFactory.java
index bbf5cd5..33fbcc3 100644
--- a/src/test/java/freemarker/core/EpochMillisTemplateDateFormatFactory.java
+++ b/src/test/java/freemarker/core/EpochMillisTemplateDateFormatFactory.java
@@ -27,22 +27,26 @@ import freemarker.template.TemplateModelException;
 
 public class EpochMillisTemplateDateFormatFactory extends TemplateDateFormatFactory {
 
-    public static final EpochMillisTemplateDateFormatFactory INSTANCE = new EpochMillisTemplateDateFormatFactory();
+    public static final EpochMillisTemplateDateFormatFactory INSTANCE
+            = new EpochMillisTemplateDateFormatFactory();
     
     private EpochMillisTemplateDateFormatFactory() {
         // Defined to decrease visibility
     }
     
     @Override
-    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
-            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
+    public TemplateDateFormat get(String params, int dateType,
+            Locale locale, TimeZone timeZone, boolean zonelessInput,
+            Environment env)
+            throws InvalidFormatParametersException {
         TemplateFormatUtil.checkHasNoParameters(params);
         return EpochMillisTemplateDateFormat.INSTANCE;
     }
 
     private static class EpochMillisTemplateDateFormat extends TemplateDateFormat {
 
-        private static final EpochMillisTemplateDateFormat INSTANCE = new EpochMillisTemplateDateFormat();
+        private static final EpochMillisTemplateDateFormat INSTANCE
+                = new EpochMillisTemplateDateFormat();
         
         private EpochMillisTemplateDateFormat() { }
         

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/test/java/freemarker/manual/CustomFormatsExample.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/manual/CustomFormatsExample.java b/src/test/java/freemarker/manual/CustomFormatsExample.java
new file mode 100644
index 0000000..31de217
--- /dev/null
+++ b/src/test/java/freemarker/manual/CustomFormatsExample.java
@@ -0,0 +1,73 @@
+package freemarker.manual;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+import freemarker.core.AliasTemplateDateFormatFactory;
+import freemarker.core.AliasTemplateNumberFormatFactory;
+import freemarker.core.BaseNTemplateNumberFormatFactory;
+import freemarker.core.TemplateDateFormatFactory;
+import freemarker.core.TemplateNumberFormatFactory;
+import freemarker.template.Configuration;
+import freemarker.template.TemplateException;
+
+@SuppressWarnings("boxing")
+public class CustomFormatsExample extends ExamplesTest {
+
+    @Test
+    public void aliases1() throws IOException, TemplateException {
+        Configuration cfg = getConfiguration();
+
+        Map<String, TemplateNumberFormatFactory> customNumberFormats
+                = new HashMap<String, TemplateNumberFormatFactory>();
+        customNumberFormats.put("price", new AliasTemplateNumberFormatFactory(",000.00"));
+        customNumberFormats.put("weight", new AliasTemplateNumberFormatFactory("0.##;; roundingMode=halfUp"));
+        cfg.setCustomNumberFormats(customNumberFormats);
+
+        Map<String, TemplateDateFormatFactory> customDateFormats
+                = new HashMap<String, TemplateDateFormatFactory>();
+        customDateFormats.put("fileDate", new AliasTemplateDateFormatFactory("dd/MMM/yy hh:mm a"));
+        customDateFormats.put("logEventTime", new AliasTemplateDateFormatFactory("iso ms u"));
+        cfg.setCustomDateFormats(customDateFormats);
+
+        addToDataModel("p", 10000);
+        addToDataModel("w", 10.305);
+        addToDataModel("fd", new Date(1450904944213L));
+        addToDataModel("let", new Date(1450904944213L));
+        
+        assertOutputForNamed("CustomFormatsExample-alias1.ftlh");
+    }
+
+    @Test
+    public void aliases2() throws IOException, TemplateException {
+        Configuration cfg = getConfiguration();
+
+        Map<String, TemplateNumberFormatFactory> customNumberFormats
+                = new HashMap<String, TemplateNumberFormatFactory>();
+        customNumberFormats.put("base", BaseNTemplateNumberFormatFactory.INSTANCE);
+        customNumberFormats.put("oct", new AliasTemplateNumberFormatFactory("@base 8"));
+        cfg.setCustomNumberFormats(customNumberFormats);
+        
+        assertOutputForNamed("CustomFormatsExample-alias2.ftlh");
+    }
+
+    @Test
+    public void modelAware() throws IOException, TemplateException {
+        Configuration cfg = getConfiguration();
+
+        Map<String, TemplateNumberFormatFactory> customNumberFormats
+                = new HashMap<String, TemplateNumberFormatFactory>();
+        customNumberFormats.put("ua", UnitAwareTemplateNumberFormatFactory.INSTANCE);
+        cfg.setCustomNumberFormats(customNumberFormats);
+        cfg.setNumberFormat("@ua 0.####;; roundingMode=halfUp");
+
+        addToDataModel("weight", new UnitAwareTemplateNumberModel(1.5, "kg"));
+        
+        assertOutputForNamed("CustomFormatsExample-modelAware.ftlh");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/test/java/freemarker/manual/UnitAwareTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/manual/UnitAwareTemplateNumberFormatFactory.java b/src/test/java/freemarker/manual/UnitAwareTemplateNumberFormatFactory.java
new file mode 100644
index 0000000..df179d4
--- /dev/null
+++ b/src/test/java/freemarker/manual/UnitAwareTemplateNumberFormatFactory.java
@@ -0,0 +1,62 @@
+package freemarker.manual;
+
+import java.util.Locale;
+
+import freemarker.core.Environment;
+import freemarker.core.TemplateNumberFormat;
+import freemarker.core.TemplateNumberFormatFactory;
+import freemarker.core.TemplateValueFormatException;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateNumberModel;
+
+/**
+ * A number format that takes any other number format as parameter (specified as a string, as
+ * usual in FreeMarker), then if the model is a {@link UnitAwareTemplateNumberModel}, it  shows
+ * the unit after the number formatted with the other format, otherwise it just shows the formatted
+ * number without unit.
+ */
+public class UnitAwareTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
+
+    public static final UnitAwareTemplateNumberFormatFactory INSTANCE
+            = new UnitAwareTemplateNumberFormatFactory();
+
+    private UnitAwareTemplateNumberFormatFactory() {
+        // Defined to decrease visibility
+    }
+
+    @Override
+    public TemplateNumberFormat get(String params, Locale locale, Environment env)
+            throws TemplateValueFormatException {
+        return new UnitAwareNumberFormat(env.getTemplateNumberFormat(params, locale));
+    }
+
+    private static class UnitAwareNumberFormat extends TemplateNumberFormat {
+
+        private final TemplateNumberFormat innerFormat;
+
+        private UnitAwareNumberFormat(TemplateNumberFormat innerFormat) {
+            this.innerFormat = innerFormat;
+        }
+
+        @Override
+        public String formatToPlainText(TemplateNumberModel numberModel)
+                throws TemplateModelException, TemplateValueFormatException {
+            String innerResult = innerFormat.formatToPlainText(numberModel);
+            return numberModel instanceof UnitAwareTemplateNumberModel
+                    ? innerResult + " " + ((UnitAwareTemplateNumberModel) numberModel).getUnit()
+                    : innerResult;
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return innerFormat.isLocaleBound();
+        }
+
+        @Override
+        public String getDescription() {
+            return "unit-aware " + innerFormat.getDescription();
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/test/java/freemarker/manual/UnitAwareTemplateNumberModel.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/manual/UnitAwareTemplateNumberModel.java b/src/test/java/freemarker/manual/UnitAwareTemplateNumberModel.java
new file mode 100644
index 0000000..fc58431
--- /dev/null
+++ b/src/test/java/freemarker/manual/UnitAwareTemplateNumberModel.java
@@ -0,0 +1,25 @@
+package freemarker.manual;
+
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateNumberModel;
+
+public class UnitAwareTemplateNumberModel implements TemplateNumberModel {
+
+    private final Number value;
+    private final String unit;
+    
+    public UnitAwareTemplateNumberModel(Number value, String unit) {
+        this.value = value;
+        this.unit = unit;
+    }
+
+    @Override
+    public Number getAsNumber() throws TemplateModelException {
+        return value;
+    }
+
+    public String getUnit() {
+        return unit;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/test/resources/freemarker/manual/CustomFormatsExample-alias1.ftlh
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/manual/CustomFormatsExample-alias1.ftlh b/src/test/resources/freemarker/manual/CustomFormatsExample-alias1.ftlh
new file mode 100644
index 0000000..abf6dfe
--- /dev/null
+++ b/src/test/resources/freemarker/manual/CustomFormatsExample-alias1.ftlh
@@ -0,0 +1,4 @@
+${p?string.@price}
+${w?string.@weight}
+${fd?string.@fileDate}
+${let?datetime?string.@logEventTime}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/test/resources/freemarker/manual/CustomFormatsExample-alias1.ftlh.out
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/manual/CustomFormatsExample-alias1.ftlh.out b/src/test/resources/freemarker/manual/CustomFormatsExample-alias1.ftlh.out
new file mode 100644
index 0000000..a15bd01
--- /dev/null
+++ b/src/test/resources/freemarker/manual/CustomFormatsExample-alias1.ftlh.out
@@ -0,0 +1,4 @@
+10,000.00
+10.31
+23/Dec/15 10:09 PM
+2015-12-23T21:09:04.213Z

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/test/resources/freemarker/manual/CustomFormatsExample-alias2.ftlh
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/manual/CustomFormatsExample-alias2.ftlh b/src/test/resources/freemarker/manual/CustomFormatsExample-alias2.ftlh
new file mode 100644
index 0000000..ae64acb
--- /dev/null
+++ b/src/test/resources/freemarker/manual/CustomFormatsExample-alias2.ftlh
@@ -0,0 +1 @@
+${10?string.@oct}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/test/resources/freemarker/manual/CustomFormatsExample-alias2.ftlh.out
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/manual/CustomFormatsExample-alias2.ftlh.out b/src/test/resources/freemarker/manual/CustomFormatsExample-alias2.ftlh.out
new file mode 100644
index 0000000..3cacc0b
--- /dev/null
+++ b/src/test/resources/freemarker/manual/CustomFormatsExample-alias2.ftlh.out
@@ -0,0 +1 @@
+12
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/test/resources/freemarker/manual/CustomFormatsExample-modelAware.ftlh
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/manual/CustomFormatsExample-modelAware.ftlh b/src/test/resources/freemarker/manual/CustomFormatsExample-modelAware.ftlh
new file mode 100644
index 0000000..49ce264
--- /dev/null
+++ b/src/test/resources/freemarker/manual/CustomFormatsExample-modelAware.ftlh
@@ -0,0 +1,2 @@
+${10.12356}
+${weight}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f112ed6c/src/test/resources/freemarker/manual/CustomFormatsExample-modelAware.ftlh.out
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/manual/CustomFormatsExample-modelAware.ftlh.out b/src/test/resources/freemarker/manual/CustomFormatsExample-modelAware.ftlh.out
new file mode 100644
index 0000000..22e0890
--- /dev/null
+++ b/src/test/resources/freemarker/manual/CustomFormatsExample-modelAware.ftlh.out
@@ -0,0 +1,2 @@
+10.1236
+1.5 kg
\ No newline at end of file