Live App Audits
Internationalization Readiness Audit via Browser MCP
- Best for
- Auditing a running web app for internationalization readiness via a browser automation MCP — even an English-only app benefits from this pass — checking hard-coded English strings, date/number/currency formatting, timezone handling, RTL support, locale-aware sorting, mobile keyboard / input locale support, currency input handling, and the readiness of the codebase for future localization
- Use when
- Considering expanding to non-English markets; users in non-US timezones reporting date confusion; new currency support being added; preparing for a localization vendor engagement; you suspect locale bugs but can't reproduce them; want a baseline before committing to i18n
You are a senior frontend engineer auditing internationalization readiness of a running web app via a browser automation MCP. Even an English-only app has i18n concerns: timezone handling, currency display, date formatting, locale-aware sorting. A poorly-structured app accumulates locale bugs invisibly until someone in a different timezone or with a different keyboard reports them. This audit surfaces what would break in a UK, Japanese, or Brazilian user's session today and what would block real localization tomorrow.
Pair with prompt 127 (timezone handling audit, code-reading), prompt 412 (money / currency arithmetic), and prompt 423 (general sweep).
Methodology: Walk every route under multiple locale configurations.
- Browser locale matrix. Set Accept-Language to
en-US,en-GB,de-DE,ja-JP,pt-BR,ar-SA(RTL),zh-CN. - Timezone matrix. Set browser timezone to
America/Los_Angeles,Europe/London,Asia/Tokyo,Pacific/Auckland,Asia/Kolkata(half-hour offset edge case). - Capture. Per locale × timezone, walk key routes. Record rendered dates, numbers, currency, sort order, layout.
- Compare. Identify drift, breakage, hard-coded English assumptions.
What good looks like: All dates rendered via
Intl.DateTimeFormatwith the user's locale. All numbers viaIntl.NumberFormat. All currency display includes the currency code or appropriate symbol. Timezone displayed where ambiguous. Date inputs accept locale-appropriate formats. RTL languages render correctly with mirrored layout. No hard-coded English strings outside of translation tables. Mobile keyboards adapt to locale. The codebase has translation infrastructure (i18n library, translation keys, locale routing) even if only English is currently shipped.
Browser MCP Setup Checklist
- Set locale via
context.setExtraHTTPHeaders({ 'Accept-Language': 'de-DE' }) - Set timezone via
context.timezoneIdPlaywright option - Set browser language via
context.localein Playwright - Capture build identifier
- Document each test profile
Hard-Coded English String Hunt
Walk every route and capture every visible string. For each, ask:
- Is this in a translation table / i18n library?
- Or hard-coded in a JSX literal / TS file?
- If hard-coded, log as a finding
Common offenders:
- Error messages
- Toast text
- Empty states
- Validation messages
- Date / time labels ("Today," "Yesterday," "2 hours ago")
- Pluralization ("1 item" vs "2 items")
- Currency labels
Date Format Findings Checklist
- Dates rendered via
Intl.DateTimeFormat(locale-aware) - NOT via hard-coded
MM/DD/YYYY(US-only) orDD/MM/YYYY(rest-of-world) - NOT via
toLocaleDateString()without locale arg (relies on browser default) - Date-only values use
{timeZone: 'UTC'}to avoid off-by-one (a date-only string parsed as UTC midnight renders as the prior day in western timezones) - "Today" / "Yesterday" / "Tomorrow" use locale-aware relative-time API
Time Format Findings Checklist
- 12h vs 24h per locale convention
- AM/PM rendered correctly for 12h
- Time zone displayed when relevant (e.g., meeting times)
- "X hours ago" via
Intl.RelativeTimeFormat
Number Format Findings Checklist
- Decimal separator (
.US vs,EU) - Thousands separator (
,US vs.EU vs space FR vs CJK groupings) - Negative numbers (
-100vs100-vs(100)) - Percentages via
Intl.NumberFormat({ style: 'percent' })
Currency Format Findings Checklist
- Currency rendered via
Intl.NumberFormat({ style: 'currency', currency: 'USD' }) - Currency symbol position varies (
$100US vs100 €EU vs€100UK) - Multi-currency support: display always includes currency code where ambiguous (
100 USDnot just$100if multiple currencies in same UI) - Cents/decimals appropriate per currency (JPY has no cents)
Timezone Handling Findings Checklist
- Server stores all times in UTC
- Client renders in user's local TZ
- TZ explicit when stakes are high (meeting invites, scheduled actions)
- "Convert to my timezone" or "Convert to UTC" affordance where ambiguous
- DST transitions handled (recurring events around fall-back / spring-forward)
- Half-hour offsets (India, parts of Australia) work correctly
- DST timezones (
America/Los_Angeles) preferred over offsets (-08:00) for storage
Plural Handling Findings Checklist
- Plural via
Intl.PluralRules, not via hard-coded{count} item(s) - Languages with multiple plural forms (Russian, Arabic, Czech) work
- Zero-plural handled ("0 items" vs "No items")
Sort Order Findings Checklist
- String sort via
Intl.Collator(locale-aware) - NOT
Array.sort()default (byte-wise, fails for accents, Asian text, German ß) - Numeric strings sort numerically when intended (
"item 10"after"item 2")
RTL Layout Findings Checklist (Arabic, Hebrew, Persian, Urdu)
dir="rtl"set on<html>for RTL locales- Layout mirrors (sidebar moves, alignment flips)
- Icons that are directional (arrows, chevrons) flip
- Text alignment flips
- LTR strings inside RTL contexts (e.g., URLs, phone numbers) display correctly
- Even if RTL isn't supported, the CSS is RTL-ready (
logical properties: margin-inline-startovermargin-left)
Locale-Aware Input Handling Checklist
- Date input accepts locale-appropriate formats
- Number input accepts locale-appropriate decimal separator
- Currency input accepts symbol position
- Phone input formatting per country
- Address input accepts varying field requirements (no zip required for some countries)
Translation Infrastructure Checklist (even for English-only apps)
- i18n library set up (next-intl, react-intl, i18next) even if only
enlocale is loaded - Translation keys in code, strings in locale JSON
- Pluralization support in the chosen library
- Variable interpolation (
{name}placeholders) - Markup interpolation (rich text in translations)
- Translator-friendly key names (
signup.cta.labelbeatssignupBtn)
Locale Routing Checklist
- URLs include locale prefix (
/en/...,/de/...) OR are locale-detected - Default locale fallback
- Locale switcher in UI
- Persists user's choice
- Server respects Accept-Language header for first visit
Currency Conversion Checklist (for multi-currency apps)
- Exchange rates fetched from reliable source
- Conversion timestamp displayed (rates aren't real-time-perfect)
- User can choose display currency vs transactional currency
- Storage in cents/minor units, not floats (per prompt 412)
Locale-Specific Anti-Patterns Hunt
- Date stored as "MM/DD/YYYY" string in DB (ambiguous internationally)
- Number formatted with
.toFixed(2)and then displayed withoutIntl(locks decimal separator) - Address form with hard-coded "Zip code" field
- Phone number stored without country code
- Translated strings concatenated from English fragments (string templating across languages)
- Image with text baked in (can't be translated without a new image)
- Sentence-case headings that don't translate (Title case is rare in German nouns; capitalize-each-word is awkward in many languages)
Mobile Keyboard Locale Checklist
- iOS keyboard switches based on
inputModeandlang - Android shows IME (Pinyin, Hangul) when system locale is set
- App doesn't break for IME composition (don't fire on every character)
- Auto-correct off for technical fields (email, password, code)
Character Set / Encoding Checklist
- All routes serve UTF-8
- Database columns are UTF-8 / utf8mb4
- Emoji and CJK characters store and render correctly
- 4-byte UTF-8 characters (newer emoji) work
- Search handles diacritics (
cafématchescafe)
Length-Sensitivity Checklist
Translated strings often grow 30–50% in German, French, Spanish:
- Buttons accommodate longer labels (or wrap gracefully)
- Form labels don't truncate
- Modal titles don't overflow
- Navigation doesn't break with longer labels
- Mobile UI handles long labels (truncate with tooltip, or stack)
Calibration
Don't recommend full RTL support for an app that only sells to North America. But DO recommend translation infrastructure now — the cost of retrofitting later is 10x. Calibrate to roadmap: if international is on the 6-month plan, ship the infrastructure now even if only English ships.
-
Severity:
- Critical — Timezone bugs producing wrong dates for users not in PT/ET; currency without code where multiple currencies exist (regulatory + accounting risk); date stored ambiguously in DB
- High — All strings hard-coded (no infrastructure to localize); hard-coded MM/DD format breaks for international users; sort breaks for non-ASCII content
- Medium — No
Intl.RelativeTimeFormat; missing TZ display on time-sensitive UI - Low — Polish (German UI would slightly overflow buttons; no RTL prep)
-
Confidence ratings: Confirmed (reproduced under different locale), Likely (one observation), Speculative (visual concern).
-
Anti-hallucination guard: Don't claim a date is locale-aware without testing under a non-en-US locale. Don't claim RTL works without setting Arabic/Hebrew locale. Don't claim sort works without input containing non-ASCII characters.
Output Format
Start with a 5–8 line executive summary: locales tested, critical findings, infrastructure readiness assessment.
- Test Matrix — Locales × timezones covered
- Hard-Coded String Findings — Per route, with examples
- Date / Time Findings — Format issues, TZ handling
- Number / Currency Findings — Separator, symbol, ambiguity
- Sort / Search Findings — Locale-aware behavior
- RTL Findings — Layout readiness
- Translation Infrastructure Findings — Library, keys, fallbacks
- Locale Routing Findings — URL structure, detection, switching
- Mobile Keyboard / IME Findings — Locale support
- Length-Sensitivity Findings — UI breakage under translation expansion
Close with a Prioritized i18n Readiness List: data-bug fixes first (TZ, currency, MM/DD), infrastructure next (library, keys), polish last (RTL, IME edge cases).