Skip to content

Locale Translation Workflow

SafeCall supports two kinds of translation locales:

  • Site-local locale: created in one installation through the admin UI. It is usable immediately on that installation only.
  • Promoted locale: committed to the project catalogs and seeded by migrations, so it ships to every installation in a release.

Create a Site-Local Locale

  1. Log in as an admin.
  2. Open System > Translations.
  3. Click Add locale.
  4. Enter a locale code such as el, a display label such as Ελληνικά, and choose a source locale to copy from.
  5. Translate values in the editor and save them.

The new locale appears in user settings once it is enabled in the local database.

Export a Locale

From the admin UI, choose the locale in Translations and click Export locale.

For direct database export, use:

sh
bun scripts/i18n/export-db-locale.ts --db server/db/safecall.db --locale el --out exports/el.json

The export format is JSON:

json
{
  "version": 1,
  "locale": { "code": "el", "label": "Ελληνικά", "is_promoted": false },
  "exported_at": 1710000000,
  "entries": [
    { "key": "shared.settings.language_label", "page": "shared.settings", "value": "Γλώσσα" }
  ]
}

Promote a Locale Into the Product

Use the promotion script on an exported JSON file:

sh
bun scripts/i18n/promote-locale.ts --input exports/el.json

The script validates key, page, and placeholder parity against the English catalog, then writes:

  • lib/src/ui_translation_el_catalog.ts
  • server/migrations/044_seed_ui_translations_el_catalog.ts

After promotion, add the locale code and label to lib/src/locale.ts, regenerate migration embeds, and run validation.

Override Policy

Catalog migrations define default translations for new installations and upgrades. Site-local admin edits are runtime database values.

New promoted-locale seed migrations should use ON CONFLICT DO NOTHING for values by default, so existing client edits are not overwritten unexpectedly. Use a dedicated update migration only when an official translation should intentionally replace existing values.

Keryx Flutter and cross-surface parity

Keryx uses Flutter gen-l10n (keryx/l10n/app_{en,cs}.arb). SafeCall admin provisioning for Keryx uses the same promoted en/cs UI catalogs. See Keryx localization policy for glossary, fallback rules, and pre-store parity checklist.