Part 7 · 2 chapters · ~12 min

Accessible APIs and Docs, Internationalisation on the Server

API documentation that people with screen readers and low bandwidth can use, plain-language errors, examples in several languages, server-side internationalisation (locale negotiation, ICU messages, plural rules), money, dates and time zones, names and addresses across cultures, and Unicode handling.

12

Docs and errors people can use

API consumers include developers using screen readers, slow connections and translation tools. Accessible docs use real headings and semantic HTML, text alternatives for diagrams, code samples as text (never images), sufficient contrast, keyboard-navigable consoles, and pages that work on 3G. Errors should say what went wrong and what to do, in plain language, with a stable machine-readable code:

code
{ "type": "https://api.example.com/errors/insufficient-funds",
  "title": "Insufficient funds", "status": 422, "code": "insufficient_funds",
  "detail": "The account has ₦4,200.00 available; the transfer needs ₦5,000.00.",
  "instance": "/v1/transfers/tr_81" }                        // RFC 9457 problem details
13

Internationalisation on the server

code
// locale negotiation, ICU plurals and currency formatting
const locale = negotiate(req.headers['accept-language'], ['en-NG', 'yo-NG', 'ha-NG', 'fr']) ?? 'en-NG';
const fmt = new Intl.NumberFormat(locale, { style: 'currency', currency: 'NGN' });
fmt.format(4200)                                         // "₦4,200.00" in en-NG
msg(locale, 'pending_transfers', { count: 3 })           // ICU: "{count, plural, one {# pending transfer} other {# pending transfers}}"

// store instants in UTC, render in the user's zone; Nigeria is Africa/Lagos (UTC+1, no DST)
new Intl.DateTimeFormat('en-NG', { timeZone: 'Africa/Lagos', dateStyle: 'medium', timeStyle: 'short' }).format(new Date());

// Unicode: normalise before comparing (NFC), count graphemes not bytes for limits
'Adéọlá'.normalize('NFC');  [...new Intl.Segmenter('yo', { granularity: 'grapheme' }).segment(name)].length
pitfallpractice
first name / last name fieldsone full-name field plus an optional preferred name; no assumptions about order
names with diacritics (Yoruba tone marks)UTF-8 end to end, NFC normalisation, no ASCII-only validation
addressesfree-form lines; postcodes optional (many Nigerian addresses have none)
moneyinteger minor units plus ISO 4217 currency; format only at the edge