What is translated where
@repo/i18n
packages/i18n holds the locale config and the translation files that the server needs.
Six locales are supported:
he, en, ar, de, es, fr. Hebrew and Arabic are right to left.
Translation files
saas.json is in this package because the package was ported from the web app. The server reads the mail scope. The web app has its own copy of these files in its own repo.
How messages are loaded
getMessagesForLocale(locale, scope):
- Reads
<locale>/<scope>.jsonand<locale>/shared.jsonfrom disk and merges them. - If the locale is not the default, loads the same two files for the default locale (
he) and merges the requested locale on top.
fs relative to the compiled module (import.meta.url). A dynamic import() of JSON did not survive bundling. The build script copies the files:
@repo/i18n, or the running API keeps the old text.
How locale is resolved
There is no locale middleware on/v1. The domain API does not read Accept-Language or any locale header.
Studio.locale defaults to he and Studio.timezone to Asia/Jerusalem in the schema. User.locale is optional.
Push notification text
Push text is configuration, not translation. Each studio edits its own titles and bodies in the notification settings, and those strings are stored inStudioNotificationConfig. The fallbacks in NOTIFICATION_CONFIG_DEFAULTS are written in Hebrew.
A studio that works in another language changes the text in settings. There is no per trainee language for push.
Hebrew in code
Several modules contain Hebrew string literals on purpose:modules/form-sign/: every error the signing page shows.modules/assistant/andmodules/agent/: system prompts, canned replies, cap and error messages.modules/plan-import/ocr.tsand the structurers: prompts.ai/nutrition-analyzer.ts: the prompt is English but instructs the model to answer with Hebrew names and notes.modules/trainee/trainee.service.ts: the display name for a deleted trainee.modules/foods/food-enums.ts: household measure and unit labels.- Sorting by name uses
localeCompare(other, 'he')in a few list builders.
@repo/i18n without a reason, because that package is consumed from dist and the strings would be far from the code that depends on their exact wording (tests pin some of them).
Catalog data
Exercise names, instructions and food names are data. The Hebrew exercise catalog and instructions are imported from files underapps/core-api/src/scripts/data/ by the import scripts. Localized display of that data is handled by the clients.
Rules for new server text
- An error on
/v1: write a short English message for developers and logs. If a client must react to it, add a stabledetails.reason. The client translates. - An error a coach reads directly (automation API, MCP): write a full English sentence that says what to fix.
- An email: add a template and keys in
mail.jsonfor all six locales. See Mail. - A push: add a notification type with default text and let studios edit it. See Notifications and push.
- Never build a user facing sentence by concatenating translated fragments. Hebrew and Arabic word order and direction break it.
- Direction: any server rendered document (email, PDF) must set direction from
getLocaleDirection. The signed PDF renderer has its own bidirectional text handling inmodules/form-sign/visual-text.ts.