Best for
- Preparing a codebase for its first translation
- Finding the strings the last sweep missed (there are always more)
- Keeping a translated product from regressing to hardcoded
What you give it
- The codebase and your message-file setup (or it proposes the shape)
What you get back
- The inventory: every user-facing string, its location, its surface — counted, so progress is a number
- Strings externalised with consistent keys and translator context notes
- The sneaky classes handled: concatenations restructured, plurals done right, formats delegated
How it works
- Sweeps beyond the obvious: components, then errors, validation messages, emails, notifications, titles, aria labels, API messages users see.
- Distinguishes user-facing from internal (log lines, codes) — moving everything is as wrong as moving nothing.
- Restructures the untranslatable patterns: concatenated fragments become whole messages with placeholders; English plural hacks become plural rules.
- Guards the future: the lint rule or pseudo-locale check that keeps the count at zero.
Example
You: We are adding German in Q2. Find and externalise everything.
Result: The sweep found 847 user-facing strings — 300 in components (expected), 212 in validation and error paths, 95 in emails, 41 in seeds and fixtures that surface to users, and 14 building sentences by concatenation ('You have ' + n + ' items') — restructured to parameterised messages with plural forms. Keys follow one grammar, each has a translator note where ambiguous ('Open — verb, button'). The lint rule added: new hardcoded strings now fail review.
Limits — please read
- Dynamic strings built from data need case-by-case design; they are listed with proposals, not bulk-converted.
- Translation itself is the next step; this sweep makes it possible and prices it (the string count).
- Source-language quality issues found on the way are flagged, not silently rewritten.