Localisation
Two layouts, auto-detected, never configured. If a folder named
defaultLocale exists at the content root the project is foldered; otherwise it
is in root mode.
# Root mode — a single-language site pays no nesting cost
content/
_index.yml ← default locale
de/_index.yml
# Foldered mode — recommended for any multi-locale site
content/
en/_index.yml
de/_index.yml
Content at the root and a default-locale folder both existing is a build-time
error (AMBIGUOUS_LOCALE_LAYOUT), not a silent preference.
Declaring locales
defaultLocale: 'en',
locales: ['en', 'de', 'fr'],
defaultLocale must appear in locales. A locale not in the list is rejected
wherever it is used — component prop, API option or route.
Resolving the current locale
The locale comes from the route: a pathname starting with a declared locale
segment (/de/about) resolves to that locale, everything else to
defaultLocale. Pass locale explicitly to any component or server function to
override it.
copy-ink does not route for you. Use Next's own i18n routing (or your own segment) and copy-ink follows the resulting pathname.
Fallback
localeFallback decides what happens when a locale's file is missing a field:
| Value | Behaviour |
|---|---|
'default' (default) | Fall back to the default locale's value |
'empty' | Render nothing |
Falling back is usually right for a site being translated incrementally — a
half-translated page beats an empty one. 'empty' is the honest choice when a
missing translation should be visible rather than papered over.
Images fall back independently: see locale fallback for images.
Checking parity
npx copy-ink i18n
Compares locales key by key and reports what is missing where, including collection items whose slug exists in one locale but not another. It exits non-zero on errors, so it drops straight into CI.
The root-mode collision
Root mode has one collision it cannot avoid: a route segment whose name matches
a declared locale. A /de page that is not the German translation is
unresolvable — content/de/ is a locale folder by definition.
copy-ink check flags it as locale-collision and tells you to migrate:
npx copy-ink migrate --locale-folders --dry-run # preview
npx copy-ink migrate --locale-folders # do it
That is a pure file move — content is never rewritten — and it moves the public image mirror alongside. Afterwards the project is in foldered mode and the collision is gone.
If you know the site will be multi-locale, start foldered and skip the whole question.
The editor
The floating toolbar has a locale switcher. Switching changes which locale the client is editing; the page itself is not re-routed, so they see the same page with the other locale's content. Changes to different locales accumulate in the same changeset and publish in one commit.