Formatting and locale / Names, addresses and identifiers
Name order and the assumption that breaks a salutation
The assumption that a person has a given name followed by a family name, in that order, which is wrong often enough that a document built on it insults people regularly.
The defect
Systems store first name and last name, then assemble a display name and a salutation from them. Several things go wrong. Some naming conventions put the family name first, so a name entered in its natural order is stored with the fields swapped and printed reversed. Some people have one name rather than two, so a required surname field is filled with a placeholder that then appears on the document. Some have several parts that do not split into two fields at all. And a salutation built by taking the last field produces, for a meaningful fraction of recipients, a greeting addressed to the wrong part of their name, which is a specific and recognisable form of getting somebody's name wrong.
What it does to the document
Names are the most variable-length field on a document and they sit in the two places with the least spare room: the addressee block and the signature block. Size both for a long name, allow wrapping in the address and not in the signature, and never truncate a name with an ellipsis.
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.
- Store a full name as the person entered it, and treat any split into parts as derived and optional rather than as the primary record.
- Where you need a display name, use the full name. It is correct for everybody and requires no assumption.
- Do not require a family name. A single-name person is not a data error, and forcing one produces a placeholder that gets printed.
- Ask for the salutation or preferred form of address rather than deriving it. Deriving it is guessing, and the guess is visible on the document.
- Never uppercase a name to make it stand out. Case carries meaning in some names, and uppercasing loses it.
- Allow the full range of characters. A name field that rejects characters outside a narrow set is a field that rejects real names.
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.
// Store what the person entered. Parts are derived and optional.
const person = {
fullName: "Wynne Elin", // as entered, in their own order
preferredSalutation: "Dr Wynne", // asked for, not derived
};
// Display: use the full name. Correct for everybody, assumes nothing.
const onDocument = person.fullName;
// Salutation: use what was given, and fall back to something that
// needs no assumption rather than to a guessed part.
const greeting = person.preferredSalutation
? `Dear ${person.preferredSalutation},`
: "Dear Sir or Madam,";
/* Not this: a guess about which part is the family name, applied to
everybody, and visible on the page when it is wrong.
const bad = `Dear Mr ${person.lastName},`; */What people do instead
Building a salutation from a last-name field. It works for most recipients in the market the system was built for and fails for a steady minority everywhere, and each failure is a letter addressed to somebody by the wrong part of their name.
How to find out rather than assume
Put a single-name person, a person whose family name comes first, and a person with a long multi-part name through the document. All three should print correctly and none should produce a placeholder or a truncation. Then read the salutations.
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.
Address line order by country, and the postcode in the wrong place
Which lines an address has and what order they go in, both of which vary by destination and neither of which is a property of your database schema.
Alphabetical order that is not alphabetical to the reader
The order a list is sorted into, which is defined by the language rather than by the byte values of the characters.
Translated labels that no longer fit the column they were sized for
The same label in another language is frequently longer, and a layout tuned to the original wraps, clips or reflows once the translation goes in.
Phone numbers on a document somebody has to dial from abroad
A number printed in a national format, which cannot be dialled from outside the country it belongs to and gives the reader no way to work out what is missing.
Tax and registration identifiers, and the validator that rejects them
Registration numbers whose length, character set and check rules differ by country, printed and validated by systems that assume the shape of the first country they supported.
Address block, 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.