Contributing a translation
ReduceWaste ships content in many locales, read from one locale list
(i18n/locales.json) that is the single source of truth for which locales exist and which
are right-to-left. Three kinds of content are translated, each in its own place:
- App UI strings —
app/messages/<locale>/*.json. Every UI string is required to live here first; a hard-coded string in a component fails lint, so there is always a key to translate. - Docs content —
docs/src/content/docs/<locale>/**, one tree per locale, mirroring the English tree this page lives in. - Recipe and glossary content —
recipes/_i18n/<locale>/**andknowledge/glossary/<locale>.yaml. A recipe’s owni18n_keyslist names exactly which of its fields need translating (mounting, wiring, safety notes, validation check); the rest of a recipe — ids, numeric ranges, the detector binding — stays the same in every locale.
Checking your work
Section titled “Checking your work”uv run rw i18n checknpm -w app exec vitest run tests/i18nThe first checks that every locale has a translation for every required key with no unexpected extras; the second runs the app’s own i18n test suite. Both are expected to pass with zero problems before a translation change is proposed.
What never gets translated
Section titled “What never gets translated”Machine identifiers, signal ids, numeric ranges and units, and any example part numbers stay identical across every locale — only the human-facing explanation text changes.
Safety-critical text
Section titled “Safety-critical text”Translations of safety_notes and validation.check get the same scrutiny as a new
recipe’s English text: a mistranslated lockout/tagout instruction is a safety problem, not a
typo, so these fields are reviewed for accuracy against the source English, not just fluency.