add-translation
Add or change user-facing text (a UI string, email, push, SMS or error message), or add a new language. Use whenever a change shows new words to a user, or the user asks for another locale.
SKILL.md.claude/skills/add-translation/SKILL.md
GitHubAdd a string or a locale
Every user-facing string is a key in packages/i18n/messages/<locale>.json (en.json
and es.json today). .claude/rules/i18n.md has the rules.
A string
- Pick the namespace (top-level key) the surface uses:
auth,settings,dashboard,email,notification,sms,errors,mobile, … and put the key next to its siblings. Reusecommon.*for shared words (Save, Cancel). - Add it to every catalog, at the same path, in the same change. Write real translations; if you can't, say so in the pull request rather than copying English.
- ICU for anything variable:
{name},{count, plural, one {# item} other {# items}}. Never concatenate translated fragments. Arguments aren't type-checked (the catalog is imported as JSON), so pass exactly the ones the message names. - Use it:
useTranslations("<ns>")(web client, anduse-intlon mobile),getTranslationsfromnext-intl/server(web server components), the translator inapps/notificationsfor emails, push and SMS. Dates, numbers and money throughuseFormatter()/getFormatter(). - Keys the code checks for: an error code needs
errors.<CODE>; an eventworkspace.audit.events.<domain>.<fact>.v<N>(nested, liketodo.created.v1); an API-key scopeworkspace.apiKeys.scopes.<scope>; a notification categorynotificationSettings.categories.<name>.
A locale
- Copy
packages/i18n/messages/en.jsonto<code>.jsonand translate it. - Add the code to
localesand tocatalogsinpackages/i18n/src/index.ts(thesatisfiesclause makes a missing key a type error). - Right-to-left: add it to
RTLinapps/web/src/app/layout.tsx. - The language switcher (
apps/web/src/modules/shell/components/language-switcher.tsx) and mobile settings listlocales, so they pick it up.
Done when
bun run check-typespasses (web keys are checked against English).bun run --filter @repo/i18n testpasses (every catalog complete; codes, events, categories and scopes all have their keys).bun run --filter @repo/email testif an email changed.- The
i18n-checkeragent reports nothing blocking.