PrimeBrickPrimeBrick
  • Docs
  • Contact
  • MIT License
  • Documentation
  • MCP Server
  • API Catalog
  • Services
  • Libraries
PrimeBrickPrimeBrick

© 2026 PrimeBrick. MIT License. v3.11.2

github
Backend
    Roles and PermissionsWorking Together on the Same RecordManaging ModulesSigning In and MFA
    Generated
    Manual
    Developer Guide
      OverviewArchitectureAPI ConventionsEntity metadata contractEntity CRUD PipelineEntities and CRUD conventionsModule Navigation MetadataService RegistryMCP GatewayThe Service ProxyRotating Secrets EngineTranslationsAuthenticationRBACEnvironment ConfigurationCollaboration & Visual Merge
Frontend
Microservices
powered by Zudoku
Developer Guide

Translations

Every user-facing string lives in a translations table and reaches the UI as a flat dict of { dot.path.key: "translated string" }. Nothing is hardcoded in the frontend — labels, errors, page titles, entity names.

Module segregation

Each module schema owns its own translations table — keys are namespaced by module:

SchemaKey prefixContents
public.translationsapp.*chrome, auth, login, shared UI
system.translationssystem.*settings, entities, config labels, RBAC
<module>.translations<module>.*the module's own surface — same pattern for US schemas

Because each schema keeps its own table and its own cache key (translations:i18n:{schema}:{lang}), a module's strings never collide with another's — and a remote service can ship its own dict with its own schema.

The contract

Code
GET /api/v1/system/translations/{module}/{lang} → flat I18nDict (ETag/304 cached) GET /api/v1/system/translations/public/{lang} → public (unauthenticated) subset

TranslationsService (BE service) → SDK TranslationsCache — Postgres builds the dict natively with jsonb_object_agg, Redis caches it per {schema, lang} (6h TTL + invalidation-on-write). The FE merges module dicts on top of the base app.* dict — flat merge, no nesting.

Literal templates — {param} interpolation

Values may embed {name} placeholders; the FE's t(key, params) fills them:

Code
t("system.entities.customer.delete.confirm", { name: "ACME" }) // "Delete customer ACME?"

Templates are single-brace {param} — not {{}} Handlebars (that's the emailsender's template engine, a different system).

Singular / plural — the entity naming convention

Every entity carries two keys used everywhere (titles, buttons, bulk confirmations, assistant answers):

Code
system.entities.customer.singular → "customer" system.entities.customer.plural → "customers" system.entities.user_profile.singular → "User" system.entities.user_profile.plural → "Users"

Field labels follow system.entities.<entity>.<field> — the generated entity-field-reference doc lists each label_key alongside its column.

Typical key families

PatternMeaning
app.auth.*login/auth chrome
system.entities.<e>.{singular,plural,<field>}entity names + field labels
system.settings.*settings pages, config labels/descriptions
system.entities.<e>.actions.*action buttons and confirmations
config.<key>.{label,description}config_entries row labels

Authoring and CRUD

controllers/http/translations.router.ts exposes module-scoped list/create/update/softDelete/restore — the same entity machinery as everything else. Entity write bodies may piggyback translations ({entity, translations} envelope — see entity-crud-pipeline): setting a field's per-language label in the same request that edits the row.

Missing keys surface as the raw key in the UI (deliberate — visible gaps instead of silently mixed languages); the en-GB fallback dict is used only when the BE itself is unreachable.

Last modified on October 28, 2026
Rotating Secrets EngineAuthentication
On this page
  • Module segregation
  • The contract
  • Literal templates — {param} interpolation
  • Singular / plural — the entity naming convention
  • Typical key families
  • Authoring and CRUD
TypeScript