Formatting and locale / Numbers and money
Which side the currency symbol goes on, and why it matters
The symbol goes before the amount in some conventions and after it in others, with different spacing, and the choice affects both meaning and column alignment.
The defect
Placement is a convention of the locale rather than of the currency, so the same currency is written with the symbol leading in one place and trailing in another, sometimes with a space and sometimes without. Getting it wrong is not usually a misreading, it is a signal: an amount written in a form nobody local writes reads as machine output from a system that does not know where it is sending the document. The bigger practical problem is that a leading symbol and a trailing symbol want opposite alignment treatments in a column, so a system that switches placement by locale and keeps one column layout produces a ragged column in half its markets.
What it does to the document
A trailing symbol pushes the rightmost edge of the figure, so right-aligning the whole string aligns the symbols and leaves the digits ragged, which is the opposite of what a column of money needs. Splitting symbol and digits into separate cells fixes it for both placements at once.
The decisions
Reasons rather than a description of the code. Formatting rules are data that changes, so most of these are about taking the rule from a maintained source rather than encoding today's answer.
- Take placement from the locale, not from the currency, and take it from a library rather than a table you maintain.
- Give the symbol its own fixed-width box in any column of figures, so the digits align on their own edge regardless of which side the symbol sits.
- Use the currency code rather than the symbol wherever the document might be read outside the issuing country, since several currencies share a symbol.
- Keep the symbol and the amount on one line. A symbol separated from its figure by a line break is a figure with no currency.
- Do not hardcode the space. Some conventions have one, some do not, and it is part of the locale data.
- Print the code once prominently rather than repeating it on every row. A column of forty rows each carrying a three-letter code is noise.
In code
The formatting happens before the markup exists, so this is mostly code rather than CSS. The wrong version is kept in a comment where the wrong version is the thing people write.
const amount = 4180.5;
// Placement, spacing and symbol all come from the locale.
new Intl.NumberFormat("en-GB", { style: "currency", currency: "GBP" })
.format(amount); // symbol leads
new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR" })
.format(amount); // symbol trails, with a space
// Where the document may be read outside the issuing country, prefer the
// code, because several currencies share a symbol.
new Intl.NumberFormat("en-GB", {
style: "currency",
currency: "USD",
currencyDisplay: "code",
}).format(amount);
/* In a column, keep the digits on their own alignment edge:
.amount { display: grid; grid-template-columns: 28pt 1fr; }
.amount .sym { text-align: left; }
.amount .num { text-align: right; font-variant-numeric: tabular-nums; } */What people do instead
Using the symbol everywhere because it is shorter. Several currencies share the dollar sign and several share the pound sign, so a document that travels carries an amount whose currency is a guess. The code costs two characters and removes the guess.
How to find out rather than assume
Render a column of amounts under a leading-symbol locale and a trailing-symbol locale. In both, the digits should form a straight right edge. Then read an amount aloud to somebody in the destination market and see whether it sounds like something they would write.
Where the API sits in this
Nowhere, and that is worth saying plainly. This API renders HTML to PDF. By the time markup reaches it, every value in it is already a string that somebody's code produced, so there is no locale option on the render because there would be nothing for one to do. What the render controls is the page: the size, the margins, and whether the formatted value still fits the column it landed in. That is why each of these pages has a paragraph about the layout consequence, because that is the half a document adds to the general problem.
Frequently asked
Should the document use the sender's conventions or the reader's?
That is a decision rather than a fact, and the only wrong answer is not making it. The issuer's conventions are defensible for a document that is a record of what the issuer did. The recipient's are defensible for a document meant to be acted on. What fails is a document that mixes them, because a reader who sees two conventions on one page cannot tell which one any given figure is in.
Is it enough to set the document language?
No. A language attribute helps with hyphenation, with the assistive technology reading order and with anything that needs to know what language the text is in, and it changes none of the values. A date formatted as 03/04/2026 is exactly as ambiguous in a document declared as English as in one declared as anything else. The values are formatted upstream.
Why does this belong in a document reference rather than a general one?
Because a document cannot be re-rendered by its reader. On a screen a wrong format is annoying and a user can often change a setting. On paper the format is final, the layout was tuned to the string lengths of one language, and a value that grew by a few characters can push a table onto another page. The formatting problem and the pagination problem are the same problem here.
Related formatting topics
The defects that travel together, then the rest of the same group.
Decimal and thousands separators, and the factor of a thousand
The comma and the point swap roles between conventions, so the same string of characters is two amounts a thousand apart depending on who is reading it.
Negative amounts in accounting format, and the missing minus
A negative figure written with a leading minus, with parentheses, or with a trailing sign, where the conventions differ and one of them is easy to miss entirely.
Numbers and codes inside right-to-left text, in the wrong order
A left-to-right run such as an amount, a reference or a URL embedded in right-to-left text, where the boundary between the two is resolved by an algorithm and not always the way you meant.
Where the half cent goes, and why the document disagrees with itself
Which way a value exactly halfway between two representable amounts is rounded, and at which point in the calculation the rounding happens.
Multi-currency total, as a layout problem
The block this value lands in, and what it takes to make it fit.
Every formatting and locale topic
The full list, grouped by money, time, identity and generated language.
Writing systems in a PDF
The other half: whether the glyphs of a script come out shaped and joined correctly.
Values are formatted by your code before they reach the markup, so every fix on this page is upstream of the render. What the render decides is whether the result still fits.