Internationalization

Entity-level translations with locale linking.

CMS supports internationalization at the entity level — not the field level. Each translation is a separate record linked by a shared translationGroup UUID.

Setup

Define available locales in your config:


          export default config({
  locales: ["en", "pt", "fr"],
  defaultLocale: "en",
  // ...
});
        

Mark entities as translatable:


          const pages = entity("pages", {
  translatable: true,
  fields: [
    text("title", { required: true }),
    slug("slug", { unique: true, required: true }),
    object("body", { fields: [...] }),
  ],
});
        

Automatic fields

Translatable entities automatically get two extra fields:

  • locale — the entity’s locale ("en", "pt", etc.)
  • translationGroup — a UUID that links all locale variants together

You don’t define these fields — they’re injected automatically when translatable: true.

Querying by locale

Filter by locale to get content in a specific language:


          GET /api/pages?filter[locale]=en
        

Every translatable entity in the API response includes a _translations field with all sibling locales:


          {
  "data": {
    "id": "uuid-en",
    "title": "About Us",
    "slug": "/en/about",
    "locale": "en",
    "translationGroup": "uuid-group",
    "_translations": {
      "pt": { "id": "uuid-pt", "slug": "/pt/sobre" },
      "fr": { "id": "uuid-fr", "slug": "/fr/a-propos" }
    }
  }
}
        

This makes building SEO alternate links (hreflang) trivial — all the data is in a single response.

Creating translations

Use the translate endpoint to create a translation from an existing record:


          POST /api/pages/:id/translate
Content-Type: application/json

{ "locale": "pt" }
        

This:

  1. Copies the content from the source record
  2. Creates a new record with the target locale
  3. Links both records via the same translationGroup
  4. Auto-prefixes slug fields with the locale (e.g., /en/about/pt/about)
  5. Copies many-to-many relations from the source

Slug conventions

By convention, translatable slugs include the locale prefix:


          /en/about
/pt/sobre
/fr/a-propos
        

This isn’t enforced by the system — you control slug values in your content. But the translate endpoint does auto-prefix slugs when creating translations.

Previous

Hooks

Next

Media