---
title: 'Internationalization (i18n)'
description: 'Ship multiple languages from day one — locales declared in brand.config, automatic hreflang, and per-entity content translation with AI auto-translate.'
canonical: 'https://cartwright.app/docs/features/internationalization'
---

# Internationalization (i18n) (/docs/features/internationalization)



## Locales [#locales]

Supported languages live in `brand.config.ts`:

```ts
locales: ["da", "en"] as const,
defaultLocale: "da",
```

`defaultLocale` is the base language — the source text stored directly in DB fields. Add a language in one place:

```ts
locales: ["da", "en", "de"] as const,
```

`i18n/routing.ts` reads this, so `/de/...` routes and `hreflang` alternates appear automatically. A single-locale shop emits no `hreflang` (no misleading signal).

## Translating content [#translating-content]

UI strings are managed via i18nexus (`messages/<locale>.json`). Storefront **content** is translated in `/admin/translations`:

| Entity      | Translatable fields           |
| ----------- | ----------------------------- |
| Product     | name, description             |
| Category    | name, description             |
| Page        | title, body                   |
| Service     | title, shortDescription, body |
| Post (blog) | title, excerpt, body          |

Each entity stores `{ en: { title: "…" }, de: { … } }` in a `translations` JSON field. At render, `getDynamicTranslation()` returns the current locale's value, falling back to the base text. Auto-translate is built into the editor.
