Channels
Writing for translation
Four locales, one glossary. Translation is not synonym swapping — it is the same product concept in natural local language.
Locales
| Locale | Role |
|---|---|
| en-GB | Canonical source for new product strings |
| en-US | Spelling and minor idiom variants |
| pt-PT | European Portuguese — formal B2B register |
| pt-BR | Brazilian Portuguese — distinct sports and UI conventions |
Workflow
- Write or update en-GB string using glossary
- Translate with glossary terms locked — native-translator workflow for natural phrasing
- Human review for legal, trust, and pricing strings
- Run
npm run i18n:check --prefix frontendfor key parity
i18n key conventions
Mirror product structure — example pattern:
business.organizerDashboard.event.tabs.collect
- Namespace per app area (
common,business) - No English prose in keys
- New spec files must be registered in frontend
package.jsontest script
ICU and plurals
Use ICU message format for counts:
{count, plural, one {# participant} other {# participants}}Engineering contract
The ui package ships no user-facing strings. Every label, placeholder, and empty state is passed from the app. Portuguese defaults in primitives were removed — all call sites must supply locale-aware strings.
pt-PT vs pt-BR
- Do not ship one Portuguese string for both locales
- tu/você choices follow established frontend conventions per locale file
- Sports terms differ (e.g. race naming) — consult native reviewers
Sporting Scouter Content Style Guide
Component-enforceable rules: design-system.sportingscouter.com/voice. Tokens from
packages/config/tailwind/theme.css.