Skip to main content

i18n / Translatable Schema Fields

DocuDesk adopts OpenRegister's register-i18n foundation to serve and store per-language variants of user-facing string fields on its registered schemas. Translations live in the existing object JSON column — no DB migration is required.

See OR's register-i18n spec and the i18n-api-language-negotiation spec for the foundation contract. This page documents only how DocuDesk consumes that contract.

Translatable fields by schema

DocuDesk's register is at v5.5.0. The following user-facing string fields carry "translatable": true and are picked up automatically by OR's TranslationHandler::getTranslatableProperties() at render time:

SchemaSchema versionTranslatable fields
templatev1.1.0name, description, content, category
templateVersionv1.1.0name, description, changelog
dossierv1.1.0name, description
huisstijlv1.1.0name
basev1.1.0name, description
correspondencev1.1.0templateName
signingRequestv1.1.0documentName
signingSessionv1.1.0documentName
signerRecordv1.1.0displayName, declineReason
publicationConsentv1.1.0notes, objectionReason, publicationDecision
publicationProhibitionv1.1.0primaryName, reason, notes
batchCorrespondenceJobv1.1.0templateName

Adding a new translatable field is a schema-version-bump-only operation — set "translatable": true on the property and bump the schema's version. OR's normalizeTranslationsForSave() will wrap existing simple string values under the register's default language on the next write.

Language negotiation in DocuDesk

DocuDesk registers LanguageNegotiationMiddleware in Application::register() so requests that hit docudesk routes (not just OR's own routes) push the resolved language onto OR's request-scoped LanguageService. TranslationHandler reads that service when rendering objects, so the right variant comes out.

Priority order (mirrors OR's LanguageMiddleware):

  1. ?_lang=<bcp47> query parameter (canonical override)
  2. ?language=<bcp47> query parameter (alias)
  3. Accept-Language header (RFC 9110)
  4. Register default language (resolved at render time by OR)
  5. Hardcoded nl fallback

Examples — all serve the Dutch variant of the template.name field for a docudesk object served at /apps/docudesk/api/objects/template/{uuid}:

# Query override (canonical)
curl 'https://example.tld/index.php/apps/docudesk/api/objects/template/abc?_lang=nl'

# Accept-Language header
curl -H 'Accept-Language: nl,en;q=0.8' \
'https://example.tld/index.php/apps/docudesk/api/objects/template/abc'

# Return-all override
curl 'https://example.tld/index.php/apps/docudesk/api/objects/template/abc?_translations=all'

Write side

POST / PUT / PATCH requests honour X-Translation-Target-Language: <bcp47> — OR's TranslationHandler stores translatable string values under that language code:

curl -X PATCH \
-H 'Content-Type: application/json' \
-H 'X-Translation-Target-Language: en' \
-d '{"name":"Dossier with the citizen"}' \
'https://example.tld/index.php/apps/docudesk/api/objects/dossier/abc'

When X-Translation-Target-Language is absent, OR falls back to the register's default language.

Response headers

Every response from a docudesk controller emits:

  • Content-Language: <resolved-tag> — the language actually served
  • X-Content-Language-Fallback: true — present only when OR fell back because the requested language was unavailable on the object

Administrative configuration

The register's default language is set via OR's admin-settings surface (see OR's register-i18n admin panel). DocuDesk does not duplicate this configuration; operators configure it once in OR and every docudesk object inherits the same default.

Operational notes

  • No DB migration is required when adding a new translatable field. Existing simple string values are wrapped under the register's default language on the next write by OR's normalizeTranslationsForSave().
  • The OPcache must be cleared after a register-version bump for the new translatable flags to be picked up.
  • If a request asks for a language the object does not have, OR falls back through the register's configured language priority list and emits X-Content-Language-Fallback: true.

See also

  • openspec/changes/register-i18n/ — the DocuDesk adoption change
  • OpenRegister's LanguageMiddleware, LanguageService, and TranslationHandler — the foundation contract
  • tests/unit/Middleware/LanguageNegotiationMiddlewareTest.php — 10 tests covering the docudesk-side bridge