Documentation / Exploitation / Guides pratiques / Set the instance language

Set the instance language

The instance manifest's locale field picks the language behaviors write into persisted content — human-task titles, notification bodies, messages to the record — not the language of the console UI. This recipe sets that field and confirms it took effect.

Before you proceed, make sure this is the setting you actually want: see Instance vs UI locale for why these are two independent settings and what happens if you conflate them.

1. Confirm what locale affects

locale (libs/shared/src/plugin/instance.ts, InstanceManifest) is the language of the instance's own content, delivered to node behaviors as ctx.locale / ctx.t(...) (libs/shared/src/plugin/behavior.ts, PluginNodeContext):

/**
 * Langue de l'INSTANCE — celle du contenu PERSISTÉ (notifications au dossier,
 * titres de validation…). Une instance est monolingue : un établissement
 * français écrit son dossier en français.
 */
locale: z.string().default("fr"),

It does not affect the config-plane/EHR chrome, the plugin catalogue, or the plugin referential — those follow each user's own display locale (the meridian-locale cookie), resolved per request via ?locale= on /api/catalog and /api/plugins (apps/api/src/i18n.ts). Changing the instance locale will not change what the console reads in for any user.

An instance is monolingual by design: this is a one-time deployment choice, not a per-user preference, and content already written is never retranslated when you change it later.

2. Set locale in the instance manifest

In the file INSTANCE_CONFIG points at (default instance.yaml at the repo root), set:

apiVersion: meridian/instance-v1
locale: fr   # language of content PERSISTED by runs (validations, notifications)

locale is a plain string with no enum constraint in the schema — it defaults to fr if omitted. In practice the values worth using are the ones your loaded plugins actually ship translations for (next step); an arbitrary locale code is accepted at parse time but will simply fall through to untranslated strings everywhere.

3. Check plugin translation coverage for that locale

Persisted strings come from each plugin's i18n/<locale>.yaml bundle, under its free-form runtime: section (behaviors call ctx.t("some.key", params) for text that isn't derived from the manifest). @posos/clinical is a concrete example — it ships both external-plugins/clinical/i18n/fr.yaml:

runtime:
  _:
    confirm-condition.title: Ajouter la condition « {display} » ?
    acknowledge-critical.title: "Acquitter le résultat critique : {display} = {value} {unit} ?"

and external-plugins/clinical/i18n/en.yaml with the same two keys in English. For each plugin your instance requires, check whether i18n/<your-locale>.yaml exists and has a runtime: section. This is diagnostic, not a hard gate — a missing bundle never fails the boot. The resolution order (libs/shared/src/plugin/i18n.ts, resolveRuntimeKey) is:

  1. the requested instance locale's bundle,
  2. the plugin's own source locale (its manifest locale:, fr by default),
  3. the raw key itself, verbatim.

So an uncovered locale degrades to a visible-but-untranslated string in production content, not an error. meridian-plugin i18n check <plugin-dir> (libs/plugin-cli/src/commands/i18n.ts) only validates the manifest-derived keys (node labels, descriptions, value-set concepts) used for UI localization — it does not check runtime: coverage, since those keys are free-form and not derivable from the manifest. To close a translation gap in a plugin you maintain, see Translate a plugin.

4. Restart the endpoint and proxy

Both processes read the instance manifest once, at process startup, not on every request:

// apps/api/src/restate/services.ts
const instance = loadInstance();
// apps/api/src/server/api.ts
const instance = loadInstance();

There is no hot reload — a manifest edit only takes effect after both processes restart:

docker compose restart endpoint proxy

(In pnpm run dev, restart the dev process instead.)

5. Verify

GET /api/catalog echoes the locale the running proxy loaded, without needing to trigger a run:

curl -s http://localhost:4000/api/catalog | jq .instanceLocale

For end-to-end confirmation, trigger a workflow that raises a human-task from a plugin you checked in step 3 (e.g. @posos/clinical's confirm-condition) and read the validation title produced — see Add human validation for how that title reaches the record. It should read in the language you set, not the language of whichever browser you're viewing it from.

75 documents6 sectionssource : /docs · généré au build