Skip to content

Add translations (i18n) ​

What you're doing ​

Every user-visible string on a page is an i18n key, not literal text. Page titles, button labels, column headers, KPI labels, enum option labels — all keys. You supply the actual words in spk-assembly/metadata/i18n/en.json (and fr.json, de.json, … for other locales).

If a key has no entry, the UI renders the raw key (office-equipment.equipment-register.title) — ugly, and flagged by the linter.

The naming convention ​

<pluginId>.<page-name>.<what>

Examples from the tutorial:

KeyValue
office-equipment.equipment-register.titleEquipment Register
office-equipment.equipment-register.newBtnNew
office-equipment.equipment-register.column.asset_tagAsset Tag
office-equipment.equipment-register.kpi.availableAvailable
office-equipment.equipment-register.status.AVAILABLEAvailable
office-equipment.equipment-checkout.status.OVERDUEOverdue
office-equipment.application.titleOffice Equipment
office-equipment.module.titleEquipment

The complete example ​

spk-assembly/metadata/i18n/en.json (excerpt — the real file has ~70 keys):

json
{
  "office-equipment.application.title": "Office Equipment",
  "office-equipment.module.title": "Equipment",
  "office-equipment.equipment-register.title": "Equipment Register",
  "office-equipment.equipment-register.subtitle": "Office Equipment tutorial module",
  "office-equipment.equipment-register.newBtn": "New",
  "office-equipment.equipment-register.exportBtn": "Export CSV",
  "office-equipment.equipment-register.kpi.total": "Total",
  "office-equipment.equipment-register.kpi.available": "Available",
  "office-equipment.equipment-register.kpi.assigned": "Assigned",
  "office-equipment.equipment-register.column.asset_tag": "Asset Tag",
  "office-equipment.equipment-register.column.name": "Name",
  "office-equipment.equipment-register.column.status": "Status",
  "office-equipment.equipment-register.status.AVAILABLE": "Available",
  "office-equipment.equipment-register.status.ASSIGNED": "Assigned",
  "office-equipment.equipment-register.form.title": "Equipment",
  "office-equipment.equipment-register.form.asset_tag": "Asset Tag",
  "office-equipment.equipment-register.form.saveBtn": "Save",
  "office-equipment.equipment-register.form.cancelBtn": "Cancel"
}

It's a flat object — dotted keys, string values. No nesting.

Line by line — where each key type comes from ​

In a page filei18n key referenced
definition.titlethe page title
a block's properties.textKey / labelKey (with source: "static")any static label
a grid column's headerKeycolumn header
a core.select option's labelKeydropdown option label
designer.displayNameKey / descriptionKeyStudio explorer label
metadata/application/*.json titleKey, metadata/module/*.json titleKeyapp / module name

Every one of those must have a matching entry in en.json.

Adding another language ​

Add fr.json with the same keys, French values. Missing keys in fr.json fall back to en.json. The ERP picks the file by the user's locale.

Keeping it in sync automatically ​

You don't have to hand-track keys. A small script that walks your page/menu/app files collecting every *Key / headerKey / static title value, then writes en.json with a humanised default for any missing key, is the practical approach — the tutorial's build uses exactly this. The linter is your safety net.

How to verify it worked ​

bash
erp plugin test office-equipment/spk-assembly

A missing key is reported as:

I18N-001  equipment-register.json: i18n key
          "office-equipment.equipment-register.kpi.total" not found in metadata/i18n/en.json

A clean run means every referenced key resolves.

Common mistakes ​

SymptomCauseFix
UI shows office-equipment.x.y literallykey missing from en.jsonadd it (linter tells you which)
en.json is nested objectswrong shapeflat { "a.b.c": "text" }
enum chips show the raw enum valueno ...status.<VALUE> keysadd one per enum value
translation not appliedfr.json missing keys, or wrong locale on the userkeys fall back to en; check the user's locale