--- name: i18n description: Add or change user-facing text in OpenAthlete (web app Paraglide catalogs, API emails and push notifications, website) in every supported language. Use for any new or modified UI string, email or notification. --- # User-facing text Supported languages: English (`en`), French (`fr`), Italian (`it`), Spanish (`es`). French users use the informal "tu" in AI-generated text and the formal "vous" in the UI, as the existing catalogs do. ## Web app 1. Add the key to all four catalogs in `apps/web/messages/{en,fr,it,es}.json`: - use snake_case, prefixed by the feature (`full_import_started`, `calendar_day_events_label`); - write parameters as `{name}`; - add it next to related keys, not only at the end, to limit merge conflicts. 2. Use it as `m.full_import_started({ provider })`, with `import { m } from '@/paraglide/messages'`. 3. Check: ```bash pnpm check:locale-parity # same keys in every catalog pnpm web exec paraglide-js compile --project ./project.inlang --outdir ./src/paraglide ``` `pnpm find:untranslated` lists keys still in English in other catalogs. `pnpm find:unused-translations` finds dead keys. 4. Write real translations, not copies of the English. Keep the product terms consistent with the existing catalogs (search them first): training load, CTL/ATL/TSB, the names of sports. ## API emails and push notifications - Email templates in `apps/api/src/modules/notification/emails/templates/` have a `translations` object with `FR`, `EN`, `IT` and `ES`. Subjects are in `libs/shared/src/email/email.ts`. - Push texts: `apps/api/src/modules/notification/push/translations.ts`. - The user's language is `user.language` (`UserLanguage` enum). Adding a language means a Prisma enum migration (`prisma-migration` skill). ## Website `apps/website/messages/{en,fr}.json`, compiled by `pnpm website translate`. ## Verify `scripts/verify.sh` runs the parity check and compiles the catalogs. The E2E test `renders the dashboard in ` checks each locale renders.