Skip to content

Convention — backend i18n keys

What it is

The naming scheme for backend resource-string keys in ErrorMessages.resx / ErrorMessages.ar.resx. Error and validation messages follow a hierarchical, per-entity key shape so that delete-block and system-row messages compose predictably and stay in English/Arabic lockstep. Locked in MIQ-132 (decision 42) and carried through MIQ-133.

When to use it

Whenever you add a localized backend message for a lookup-CRUD entity — a referenced-block body, a system-row guard, or a validation message.

The key scheme

For an entity <Entity>:

Key Used for
<Entity>.IsSystem.Body The system-row protection message (SystemRowProtectedException<T>).
<Entity>.Referenced.Header First line of a delete-blocked-by-FK message.
<Entity>.Referenced.Intro "This … is referenced by:" lead-in.
<Entity>.Referenced.Surface.<Table> One line per referencing table (e.g. .Surface.Employees), emitted only when its count is non-zero.
<Entity>.Referenced.Footer Closing remediation line ("Reassign these…, then retry.").
<Entity>.Validation.<Rule> A FluentValidation message (e.g. Terminal.Validation.TimeZoneIdInvalid).

Real keys from ErrorMessages.resx:

Grade.Referenced.Header            = "Cannot delete {0}."
Grade.Referenced.Intro             = "This grade is referenced by:"
Grade.Referenced.Surface.Employees = "• {0} employees"
Grade.Referenced.Footer            = "Reassign these employees to other grades, then retry."
Grade.IsSystem.Body                = "This grade is a system row and cannot be modified or deleted."
Terminal.Validation.TimeZoneIdInvalid = "TimeZoneId must be a valid IANA timezone identifier (e.g. Asia/Riyadh)."

The service composes the full "referenced by" body top-to-bottom (Header → Intro → one Surface line per non-zero FK → Footer) via IStringLocalizer<ErrorMessages>. See Exceptions for how the composed body reaches the 409 response.

Gotchas / constraints

  • Both locales in lockstep. Every key added to ErrorMessages.resx must also exist in ErrorMessages.ar.resx. A frontend render test asserts en.json/ar.json parity on the FE side; keep the BE resx pair equally aligned.
  • Compose in the service. Keys are looked up and assembled in the service (where IStringLocalizer is injected), not in the controller or the exception.
  • One Surface.<Table> key per referencing FK — Terminal has 8 surfaces, Grade has 1. Name them by the referencing table.
  • This is backend product i18n — distinct from the resx-vs-i18next split covered in Internationalisation, and distinct again from the wiki's own Arabic-translation track.

Build status

Available — the scheme is live across the seven lookup entities' resx entries (MIQ-132 decision 42; MIQ-133 decision 42).