Accessibility · i18n · TypeScript at Scale

FE Lead · Lesson 23 — print before the round
One-line to open with

"These are three correctness guarantees, not features: right for every body (a11y), every locale (i18n), every refactor (TS). At 90 engineers you can't review your way there — you encode them into the platform: design system, shared i18n layer + lint, strict tsconfig + Zod + CI gates."

i18n — remove English assumptions

  • Native Intl API (CLDR built into browser): Intl.NumberFormat (currency!), DateTimeFormat, RelativeTimeFormat, ListFormat, PluralRules, Segmenter. Construct(locale,opts)→format(). Never hand-roll.
  • Plurals: Arabic 6 forms, Russian 4, JP 1 → ICU MessageFormat {n, plural, one{# hotel} other{# hotels}}. Never concatenate sentences.
  • RTL: dir="rtl" + CSS logical properties (margin-inline-start) → browser mirrors layout. No parallel RTL stylesheet.
  • Segmentation: Thai/CJK have no spaces → Intl.Segmenter, not .split(' '). (Big for SEA.)
  • SEO/routing: locale in URL (/th/…) + SSR + hreflang alternates; lazy-load only active locale bundle.

Accessibility — semantic first, ARIA last

  • Hierarchy: semantic HTML → native attrs (alt/label) → ARIA only for genuine gaps.
  • Real <button> = focusable + key-operable + announced, free. <div onClick> = none of it.
  • Keyboard: tab order logical, visible focus ring (never bare outline:none), focus management + trap on modal, move/announce focus on SPA route change.
  • Contrast 4.5:1 body (AA); never color-only signals. WCAG 2.2 SC 2.5.8: targets ≥ 24×24px.
  • Testing: axe-core in CI = floor (~⅓, programmatic). Manual keyboard + VoiceOver/NVDA = real test.

TypeScript at scale — types as contracts

  • strict: true (esp. strictNullChecks) catches the undefined is not a function class. any = type system off → prefer unknown + narrow.
  • Types erase at runtime. as User is an unchecked lie. Validate at every trust boundary (network/storage/URL/postMessage) with Zod .parse(); z.infer the type from the schema (one source of truth).
  • Shared types package = cross-team / MFE contract (fixes L14 lost-types). Breaking change fails consumer's CI typecheck, not prod.
  • Project references = enforce boundaries + incremental builds → fast CI in a big monorepo.

Lead synthesis — encode it once

GuaranteeLives in…
a11yAccessible-by-default design system (Radix/React Aria) + axe + visual-regression CI
i18nShared t()/<FormattedMessage> over Intl+ICU, extraction pipeline, lint fails on hard-coded string
TSStrict shared tsconfig, contracts package, project refs, Zod at boundaries — all gated in CI
Don't fail the interview
Memorize

Every body, every locale, every refactor. · Intl for format, ICU for plurals, logical CSS for direction, hreflang for SEO. · Semantic HTML before ARIA. · TS guards refactors (inside), Zod guards boundaries (edges) — you need both. · Encode the guarantee, don't review for it.