--- title: "Localization — Content Internationalization" aliases: [payload-localization, payload-i18n-content, payload-multilingual] tags: [payloadcms, localization, i18n, multilingual, content] sources: [raw/configuration__localization.md] created: 2026-05-15 updated: 2026-05-15 --- ## Overview Localization manages **data translations** (content in multiple languages), while [[wiki/payloadcms/i18n|I18n]] manages **UI translations** (admin panel labels). They complement each other but are separate concerns. Enable globally via `localization` key in Payload Config, then opt individual fields in with `localized: true`. ## Config Setup ```ts import { buildConfig } from 'payload' export default buildConfig({ localization: { locales: ['en', 'es', 'de'], // required defaultLocale: 'en', // required fallback: true, // default: true }, }) ``` ### Config Options | Option | Description | |--------|-------------| | `locales` | Array of locale codes or full locale objects | | `defaultLocale` | Fallback locale when none specified (required) | | `fallback` | Auto-fallback to default locale when field value missing (default: `true`) | | `filterAvailableLocales` | Async fn `({ req, locales })` → filtered locales for admin UI selector | ### Locale Object (Full Form) ```ts { code: 'ar', // required — used in API params label: 'Arabic', // shown in admin locale selector rtl: true, // enables Right-To-Left input fields fallbackLocale: 'en' // per-locale fallback (string or array) } ``` Locale codes are arbitrary — use `'en'`, `'en-US'`, `'en-UK'`, etc. ## Field-Level Localization Localization is **field-level**, not document-level. Add `localized: true` to each field: ```js { name: 'title', type: 'text', localized: true, } ``` - Works on **all field types** including `array`, `blocks`, `relationship` - Enabling on a `blocks` field localizes the **entire layout** (all nested fields) - Alternatively, localize only specific nested fields > **Warning:** Changing `localized` on an existing field changes the DB structure — existing data for that field **will be lost**. Plan a migration strategy before toggling. ## Status Localization (Experimental) Manage draft/published status **per locale** independently. Two-step setup: **Step 1 — Global flag:** ```ts experimental: { localizeStatus: true, } ``` **Step 2 — Per collection:** ```ts versions: { drafts: { localizeStatus: true, }, } ``` Result — `status` stored as object: ```ts status: { en: 'published', es: 'draft', de: 'published' } ``` ## Filtering Locales Per Tenant ```ts filterAvailableLocales: async ({ req, locales }) => { const tenant = await getTenantFromRequest(req) if (tenant?.supportedLocales?.length) { return locales.filter(l => tenant.supportedLocales.includes(l.code)) } return locales } ``` Filtering runs server-side at app root — not per page navigation. Call `router.refresh()` when `supportedLocales` changes. ## Querying Localized Documents ### REST API ``` GET /api/posts?locale=es&fallback-locale=none GET /api/posts?locale=all // returns all locales in one request ``` | Param | Values | |-------|--------| | `locale` | Any locale code, `'all'`, `'*'` | | `fallback-locale` | Locale code, `'null'`, `'false'`, `'none'` | ### GraphQL API ```graphql query { Posts(locale: de, fallbackLocale: none) { docs { title } } } ``` - Locale specified at top level auto-applies to nested relationship fields - Locale codes auto-converted to valid GraphQL enum values (dashes → underscores) ### Local API ```js const posts = await payload.find({ collection: 'posts', locale: 'es', fallbackLocale: false, }) ``` `fallbackLocale` accepts: locale string, array of locales, `'null'`, `'false'`, `false`, `'none'`. ## Key Takeaways - **Field-level granularity** — opt each field into localization individually - **`localized: true` on `blocks` = whole layout is localized** — or go field-by-field inside - **`fallback: true` (default)** — missing locale values automatically show `defaultLocale` value - **`locale=all`** in REST/Local API returns all locale values in one request (useful for admin/export) - **Status localization is experimental** — test thoroughly before production - **Data migration required** when toggling `localized` on existing fields - **`filterAvailableLocales`** enables per-tenant locale scoping in multi-tenant apps - **RTL support** built-in via `rtl: true` on locale object ## Related - [[wiki/payloadcms/i18n|I18n — Interface Internationalization]] — admin panel UI translations (separate from content) - [[wiki/payloadcms/collection-config|Collection Config]] — field definitions and schema options - [[wiki/payloadcms/rest-api|REST API]] — locale query params in detail - [[wiki/payloadcms/local-api|Local API]] — locale options in `payload.find()` / `payload.findByID()` - [[wiki/payloadcms/globals-config|Globals Config]] — globals also support localized fields ## Sources - `raw/configuration__localization.md` - https://payloadcms.com/docs/configuration/localization