Skip to content
Updated Sep 12, 2026 by Barča Dvořáková · Owner: analysisactiveconceptgeneric Edit on GitHub

translations ​

Concept layer — frozen. The Translations generic. Nothing here is written by a normal playbook run; a project's own feature analysis is the live document and takes every edit. This layer names no project and links to none — the dependency runs one way, from an application to its concept.

Feature: Translations

Entity: translations

Description: Translation entity holds data about all translation values used across the system.

Entity Type: Table

Attribute NameDescriptionData TypeDefault ValueRequired (= Nullable)UniqueFormatValidationsIndexExample
idUnique identifier for translationUUID v7Auto-generated (in code)YesYes-Must be a unique identifierPrimary Key550e8400-e29b-41d4-a716-446655440000
localeTranslation locale — one spelling, validated by pattern (see the feature page)String-YesNoLanguage + region; the project picks hyphen or underscoreMust match the project's locale patternname: idx_translations_locale, type: btreecs-CZ
translationKeyKey being translatedString-YesNo-Must not be an empty stringname: idx_translations_translationKey, type: btreeenum.education.primary, entity.account.example_bank_czk
translationTypeCategory of the translation — for example enum, entity, static contentString-YesNoShould be an enum defined by your systemMust not be an empty stringname: idx_translations_translationType, type: btreeentity.account
translationTranslated text in the required languageString-YesNo-Must not be an empty string— (no documented read filters on the text; see Reads, deletes and indexing)Základní škola
componentsComponent the translation is relevant for — a tag, not part of the identityText[]-YesNoShould be an enum defined by your systemMust not be an empty stringname: idx_translations_components, type: GIN (array overlap){web,mobile}
activeIndicates whether the translation is active or notBooleanTrueYesNo---true
createdAtTimestamp of entity creationtimestamp with time zonenow() — assigned in codeYesNoISO 8601 — YYYY-MM-DDTHH:mm:ss.SSSZ--2025-03-16T18:00:00Z
updatedAtTimestamp of last entity updatetimestamp with time zonenow() — assigned in codeYesNoISO 8601 — YYYY-MM-DDTHH:mm:ss.SSSZ--2025-03-16T18:00:00Z
deletedAtTimestamp of entity soft delete. Once set (that is, once it is non-null), this value is immutable and cannot be changed.timestamp with time zone-No-ISO 8601 — YYYY-MM-DDTHH:mm:ss.SSSZ--null
createdByIdentifier of the author who created this record.String-YesNotype:actor--user:c2d3f586-1c9a-4f5f-b9ae-45f2c4f69f7e
updatedByString that identifies the author who last updated this record.String-YesNotype:actor--system:migration

Example Data ​

sql
INSERT INTO translations (id, locale, translationKey, translation, translationType, components,
                          active, createdAt, updatedAt, deletedAt, createdBy, updatedBy)
VALUES
  ('01964a02-6990-7269-a83f-923f6308ca70', 'en-GB', 'app.offline.title',
   'No workspace connected', 'static', ARRAY['web'], true,
   '2025-04-18T18:45:00+02:00', '2025-04-18T18:45:00+02:00', null, 'seed:init', 'seed:init'),
  ('01964a02-6991-7269-80d9-a6e0dc470bce', 'en-GB', 'app.offline.description',
   'Connect to your workspace by scanning the QR code or tapping the link in your email invitation.',
   'static', ARRAY['web'], true,
   '2025-04-18T18:45:00+02:00', '2025-04-18T18:45:00+02:00', null, 'seed:init', 'seed:init'),

  -- Lookup table values
  ('01964a0c-7b3c-7c7b-8abb-ac8e6a13f811', 'en-GB', 'cs-CZ', 'Czech', 'lt.locale',
   ARRAY['web'], true,
   '2025-04-18T18:45:00+02:00', '2025-04-18T18:45:00+02:00', null, 'seed:init', 'seed:init'),
  ('01964a0c-7b3c-7c7b-8aca-ab66f659fdfc', 'en-GB', 'en-GB', 'English', 'lt.locale',
   ARRAY['web'], true,
   '2025-04-18T18:45:00+02:00', '2025-04-18T18:45:00+02:00', null, 'seed:init', 'seed:init'),
  ('01964a0c-7b3c-7c7b-8526-a1783966de5c', 'cs-CZ', 'cs-CZ', 'Čeština', 'lt.locale',
   ARRAY['web'], true,
   '2025-04-18T18:45:00+02:00', '2025-04-18T18:45:00+02:00', null, 'seed:init', 'seed:init'),
  ('01964a0c-7b3c-7c7b-89e7-8dd7fe713d9f', 'cs-CZ', 'en-GB', 'Angličtina', 'lt.locale',
   ARRAY['web'], true,
   '2025-04-18T18:45:00+02:00', '2025-04-18T18:45:00+02:00', null, 'seed:init', 'seed:init');

Identity ​

A translation is identified by locale + translationKey + translationType. Those three columns are unique together among live rows; a write for an existing triple is an update, not a second row.

components is not part of the identity. It records which clients need this translation so a client can fetch only its own subset — it is a tag on the row, not a discriminator. Two modules that genuinely need different text for a similar concept use different keys (<module>.<thing>.<property>), which is what a dot-namespaced key is for.

Why identity stops at three. Consumers are typically served a flat key → string map for one locale. If a key could appear more than once in a locale, that map cannot represent both values and one silently wins. Adding components to the identity also makes uniqueness depend on an array value, so reordering a list produces a second row rather than a conflict — a duplicate created by a formatting change.

Reads, deletes and indexing ​

  • Delete is soft. The entity defines deletedAt as immutable once set, and the sibling concepts in this layer soft-delete; a hard DELETE here would be the only one, and would contradict this document's own column.
  • Every read filters active = true and deletedAt IS NULL unless it is the administration listing explicitly asking for them. A read that ignores both makes the two columns decorative: deactivating a translation would change nothing a caller sees.
  • Index what is filtered on. Reads select by locale, translationType and components; those are the columns to index, components with a container index since it is an array. Indexing the translated text — which no documented query filters on — buys nothing, and leaving translationType unindexed while it appears in every WHERE clause is the wrong way round. Both source documents had exactly that inversion.