PDFPipe

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.

js
// 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.

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.