Runtime verified Test scripts included

Syntax

FormatCurrency(value, locale[, decimalPlaces, symbol])  →  string
2–4 arguments

Parameters

Name Type Required Description
value string | number Yes Amount to format; a numeric string works and may carry thousands separators
locale string Yes Locale supplying the symbol, its position and the separators; hyphen or underscore
decimalPlaces string | number No Overrides the locale’s own decimal count
symbol string No Replaces the symbol only; the locale still decides where it goes

Example

The usual case — hand it the amount and the reader’s locale and let the locale do the work:

%%[
  VAR @price, @locale
  SET @price = 1234.555
  SET @locale = AttributeValue("Locale")
]%%
Your total: %%=FormatCurrency(@price, @locale)=%%

With en-US that renders $1,234.56; with de-DE, 1.234,56 € — different symbol, different side, different separators, same call.

Force a whole-number amount by supplying the decimal count:

%%=FormatCurrency(1234.555, "de-CH", 0)=%%

Substitute the symbol without disturbing the layout:

%%=FormatCurrency(1234.555, "es-MX", 2, "Mex$")=%%

Return value

string — the amount rendered as currency for the requested locale.

The domain is open, so there is no set of literals to test for.

Behaviour

The locale decides six things at once: the symbol, which side of the number it sits on, the group separator, the decimal separator, the negative form, and — when the argument is omitted — how many decimals are shown. Only the symbol can be overridden.

A numeric string is accepted and formats identically to the number.

Rounding is half-up. 2.345 gave $2.35 and 2.355 gave $2.36.

The decimal count is not a flat two. ja-JP rendered no decimals at all, because the yen has no minor unit. Supplying 2 explicitly forced two decimals onto the same amount, so the argument overrides the locale rather than restating a default. It also accepts a numeric string.

The symbol argument swaps the glyph, nothing else. Mex$ with es-MX rendered in the leading position that locale uses, while CHF with de-DE rendered trailing — the layout came from the locale in both cases. It is positional, so a symbol cannot be supplied without a decimal count.

One amount, nine locales

Every row below is 1234.555 with no further arguments:

Locale Result Notes
en-US $1,234.56 symbol leading
en_GB £1,234.56 underscore form accepted
de-DE 1.234,56 € symbol trailing after a space
fr-FR 1 234,56 € group separator is a non-breaking space
ja-JP ¥1,235 no decimals — the locale’s own choice
pt-BR R$ 1.234,56 multi-character symbol, space after
hi-IN ₹1,234.56  
de-CH CHF 1’234.56 group separator is a right single quote
de 1.234,56 € language-only code works

Two of these break naive post-processing: fr-FR uses U+00A0 rather than a space, and de-CH uses U+2019 rather than an apostrophe. Neither survives a comparison written against plain ASCII.

An unknown locale does not abort. zz-ZZ rendered ¤1,234.56 with the generic currency sign U+00A4 in the leading position, and the empty string fell back to the US format — so a mistyped locale ships a wrong-looking price rather than an error.

Negatives follow the locale too

Locale -1234.555
en-US ($1,234.56)
de-DE -1.234,56 €

The US form uses brackets and no minus sign at all. Code that looks for a leading - to detect a refund misses it.

Show test script
%%[
  VAR @b, @n, @ns, @neg
  SET @b = RequestParameter("b")
  SET @n = 1234.555
  SET @ns = "1234.555"
  SET @neg = -1234.555

  /* known-good control: renders on every request, so a run of HTTP 422s
     can be told apart from a broken deploy */
  OutputLine(Concat("CTRL=[", Uppercase("ok"), "]"))

  /* which symbol, which side, which separators - and which names work */
  IF @b == "s4" THEN
    OutputLine("--- s4 start ---")
    OutputLine(Concat("enUS=[", FormatCurrency(@n, "en-US"), "]"))
    OutputLine(Concat("enUSu=[", FormatCurrency(@n, "en_US"), "]"))
    OutputLine(Concat("enGB=[", FormatCurrency(@n, "en_GB"), "]"))
    OutputLine(Concat("deDE=[", FormatCurrency(@n, "de-DE"), "]"))
    OutputLine(Concat("frFR=[", FormatCurrency(@n, "fr-FR"), "]"))
    OutputLine(Concat("jaJP=[", FormatCurrency(@n, "ja-JP"), "]"))
    OutputLine(Concat("ptBR=[", FormatCurrency(@n, "pt-BR"), "]"))
    OutputLine(Concat("hiIN=[", FormatCurrency(@n, "hi-IN"), "]"))
    OutputLine(Concat("deCH=[", FormatCurrency(@n, "de-CH"), "]"))
    OutputLine(Concat("bare=[", FormatCurrency(@n, "de"), "]"))
    OutputLine(Concat("bogus=[", FormatCurrency(@n, "zz-ZZ"), "]"))
    OutputLine(Concat("empt=[", FormatCurrency(@n, ""), "]"))
    OutputLine("--- s4 done ---")
  ENDIF

  /* decimal places, a replacement symbol, rounding and negatives */
  IF @b == "s5" THEN
    OutputLine("--- s5 start ---")
    OutputLine(Concat("dp0=[", FormatCurrency(@n, "de-CH", 0), "]"))
    OutputLine(Concat("dp2ja=[", FormatCurrency(@n, "ja-JP", 2), "]"))
    OutputLine(Concat("dp3=[", FormatCurrency(@n, "de-DE", 3), "]"))
    OutputLine(Concat("dpstr=[", FormatCurrency(@n, "en-US", "3"), "]"))
    OutputLine(Concat("sym=[", FormatCurrency(@n, "es-MX", 2, "Mex$"), "]"))
    OutputLine(Concat("symde=[", FormatCurrency(@n, "de-DE", 2, "CHF"), "]"))
    OutputLine(Concat("neg=[", FormatCurrency(@neg, "en-US"), "]"))
    OutputLine(Concat("negde=[", FormatCurrency(@neg, "de-DE"), "]"))
    OutputLine(Concat("h1=[", FormatCurrency(2.345, "en-US"), "]"))
    OutputLine(Concat("h2=[", FormatCurrency(2.355, "en-US"), "]"))
    OutputLine(Concat("numstr=[", FormatCurrency(@ns, "en-US"), "]"))
    OutputLine("--- s5 done ---")
  ENDIF
]%%

Availability

Platform Available
Marketing Cloud Engagement Yes
Marketing Cloud Next Yes (since 67)

See also