---
title: "I18n — Interface Internationalization"
aliases: [payload-i18n, internationalization, payload-translations]
tags: [payloadcms, i18n, internationalization, admin-panel, configuration]
sources: [raw/configuration__i18n.md]
created: 2026-05-15
updated: 2026-05-15
---

## Overview

Payload Admin Panel is translated into 30+ languages via `@payloadcms/translations`. I18n controls the **interface language** (labels, errors, admin UI) — not content translations (see [[wiki/payloadcms/admin-panel-overview|Admin Panel Overview]] for localization distinction).

- Language auto-detected from the request; falls back to `'en'`
- Users can change language in account settings / [[wiki/payloadcms/admin-preferences|User Preferences]]

## Setup

```bash
pnpm install @payloadcms/translations
```

```ts
// payload.config.ts
import { buildConfig } from 'payload'
import { en } from '@payloadcms/translations/languages/en'
import { de } from '@payloadcms/translations/languages/de'

export default buildConfig({
  i18n: {
    fallbackLanguage: 'en',          // default
    supportedLanguages: { en, de },  // only import what you need
  },
})
```

> **Tip:** Only add languages you actually need — each adds to the JS bundle.

## Config Options

| Option | Description | Default |
|--------|-------------|---------|
| `fallbackLanguage` | Language to use when user's preferred isn't supported | `'en'` |
| `translations` | Custom/overridden translation strings keyed by language code | — |
| `supportedLanguages` | Languages available in the app — import from `@payloadcms/translations/languages/*` | — |

## Custom Translations

### Override existing keys or add new namespaces

```ts
i18n: {
  translations: {
    en: {
      custom: {
        key1: 'Translation with {{variable}}',
      },
      general: {
        dashboard: 'Home',  // override built-in key
      },
    },
  },
}
```

### TypeScript types for custom translations

```ts
// custom-translations.ts
import { enTranslations } from '@payloadcms/translations/languages/en'
import type { NestedKeysStripped } from '@payloadcms/translations'

export const customTranslations = {
  en: {
    general: { myCustomKey: 'My custom english translation' },
    fields: { addLabel: 'Add!' },
  },
}

export type CustomTranslationsObject = typeof customTranslations.en & typeof enTranslations
export type CustomTranslationsKeys = NestedKeysStripped<CustomTranslationsObject>
```

### Using translations in Custom Components

```ts
// components/MyComponent.tsx
'use client'
import { useTranslation } from '@payloadcms/ui'
import type { CustomTranslationsObject, CustomTranslationsKeys } from '../custom-translations'

export const MyComponent = () => {
  const { t } = useTranslation<CustomTranslationsObject, CustomTranslationsKeys>()
  return t('general:myCustomKey')
}
```

## Project Translations (Collection/Field Labels)

Translate your own collection labels, field labels, placeholders, and group names by providing an object keyed to language codes:

```ts
export const Articles: CollectionConfig = {
  slug: 'articles',
  labels: {
    singular: { en: 'Article', es: 'Artículo' },
    plural:   { en: 'Articles', es: 'Artículos' },
  },
  fields: [{
    name: 'title',
    type: 'text',
    label: { en: 'Title', es: 'Título' },
    admin: {
      placeholder: { en: 'Enter title', es: 'Introduce el título' },
    },
  }],
}
```

## Node.js / Backend

- Language set on `req` before request handlers run → backend validation errors and emails use the user's language
- Send `accept-language` header in HTTP requests for language selection
- Access translations anywhere via `req.i18n` and `req.t('namespace:key')`

## Key Takeaways

- Install `@payloadcms/translations`; import only the languages you need (bundle size)
- `i18n.supportedLanguages` → which languages are available; `i18n.translations` → custom/override strings
- I18n = admin interface language; **Localization** = content data translations (different feature)
- `fallbackLanguage` defaults to `'en'`; user preference stored in [[wiki/payloadcms/admin-preferences|User Preferences]]
- Backend requests respect `accept-language` header → errors and emails use correct language
- Custom translations need TypeScript types via `NestedKeysStripped<>` — export from a shared file to avoid drift between config and components
- Use `req.t('namespace:key')` in hooks and access control functions for server-side translations

## Sources

- `raw/configuration__i18n.md`
- [Payload i18n docs](https://payloadcms.com/docs/configuration/i18n)
- [Available translations](https://github.com/payloadcms/payload/tree/main/packages/translations)
