payload-intl
v1.4.5
Published
Payload Plugin for I18N using ICU Messages
Downloads
1,552
Maintainers
Readme
payload-intl
Schema-driven internationalization for Payload CMS using ICU MessageFormat.
Overview
Define your message keys as a typed schema using ICU MessageFormat syntax, then manage translations across locales in a rich admin UI with validation, autocompletion, and support for plurals, selects, dates, and tags. Messages can be fetched server-side or client-side.
Features
- ICU MessageFormat — variables, plurals, selects, number/date/time formatting, and XML-like tags.
- Schema-driven — define message keys and templates in a typed schema with automatic validation.
- Rich editor UI — message editor with variable chips, autocompletion, and inline ICU element editors.
- JSON import — bulk-import translations from JSON files directly in the admin UI.
- Flexible storage — store translations as JSON in the database (default) or as uploaded files for CDN hosting.
Installation
pnpm add payload-intlUsage
// payload.config.ts
import { buildConfig } from "payload";
import { intlPlugin } from "payload-intl";
export default buildConfig({
localization: {
locales: ["en", "de", "fr"],
defaultLocale: "en",
},
// ...
plugins: [
intlPlugin({
schema: {
common: {
greeting: "[Main greeting] Hello {name}!",
items: "{count, plural, one {# item} other {# items}}",
},
auth: {
login: "Sign in",
logout: "Sign out",
},
},
tabs: true,
}),
],
});Scoped messages on globals
Colocate translations with the globals they belong to by adding scopes:
intlPlugin({
schema: {
navigation: { home: "Home", about: "About" },
common: { greeting: "Hello {name}!" },
},
scopes: ["navigation"],
// or with position control:
// scopes: { navigation: 'sidebar' }
// scopes: { navigation: { position: 'tab', existingFieldsTabLabel: 'Nav Fields' } }
});The navigation key will be edited on the navigation global (in a Messages tab by default), while common stays in the /intl view.
Fetch messages in your application:
import { fetchMessages } from "payload-intl";
const messages = await fetchMessages(payload, "en");Options
| Option | Type | Default | Description |
| ---------------- | ------------------------------------------------------ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| schema | MessagesSchema | — | Required. Nested object defining message keys and ICU templates. Leaf values are ICU MessageFormat strings, optionally prefixed with a [description]. |
| storage | 'db' \| 'upload' | 'db' | 'db' stores translations as JSON in the database. 'upload' stores them as uploaded .json files for CDN/static hosting. |
| scopes | MessagesScopesConfig | — | Colocate translation editing with Payload globals. Maps top-level schema keys to globals, adding a Messages tab or sidebar. Accepts an array of slugs or a record with position config. |
| tabs | boolean | false | When enabled, top-level schema keys are rendered as tabs in the admin UI. |
| collectionSlug | string | 'messages' | Slug of the collection used to store translation documents. |
| editorAccess | (req: PayloadRequest) => boolean \| Promise<boolean> | (req) => req.user !== null | Access control function that determines who can edit messages. |
| hooks | MessagesHooks | {} | Collection hooks. Extends Payload's collection hooks with an additional afterUpdate callback fired when translations are saved. |
Note: Switching between storage strategies on an existing deployment is not yet supported automatically. When the database schema changes (e.g. dropping upload columns), the migration data is lost before the app can read it. A safe migration path will be provided in a future release. For now, export your translations before switching strategies.
Contributing
This plugin lives in the payload-plugins monorepo.
Development
pnpm install
# watch this plugin for changes
pnpm --filter payload-intl dev
# run the Payload dev app (in a second terminal)
pnpm --filter sandbox devThe sandbox/ directory is a Next.js + Payload app that imports plugins via workspace:* — use it to test changes locally.
Code quality
- Formatting & linting — handled by Biome, enforced on commit via husky + lint-staged.
- Commits — must follow Conventional Commits with a valid scope (e.g.
fix(payload-intl): ...). - Changesets — please include a changeset in your PR by running
pnpm release.
Issues & PRs
Bug reports and feature requests are welcome — open an issue.
License
MIT
