payload-intl 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -221
- package/dist/components/MessageController.d.ts +4 -6
- package/dist/components/MessageController.d.ts.map +1 -1
- package/dist/components/MessageController.js +25 -41
- package/dist/components/MessageController.js.map +1 -1
- package/dist/components/MessageFormContext.d.ts +29 -0
- package/dist/components/MessageFormContext.d.ts.map +1 -0
- package/dist/components/MessageFormContext.js +30 -0
- package/dist/components/MessageFormContext.js.map +1 -0
- package/dist/components/MessagesForm.d.ts +2 -2
- package/dist/components/MessagesForm.d.ts.map +1 -1
- package/dist/components/MessagesForm.js +126 -112
- package/dist/components/MessagesForm.js.map +1 -1
- package/dist/components/MessagesForm.module.css +41 -0
- package/dist/{exports/link.d.ts → components/MessagesLink.d.ts} +3 -3
- package/dist/components/MessagesLink.d.ts.map +1 -0
- package/dist/components/MessagesLink.js +19 -0
- package/dist/components/MessagesLink.js.map +1 -0
- package/dist/components/MessagesView.d.ts +10 -0
- package/dist/components/MessagesView.d.ts.map +1 -0
- package/dist/components/MessagesView.js +48 -0
- package/dist/components/MessagesView.js.map +1 -0
- package/dist/components/actions/JsonImport.d.ts.map +1 -1
- package/dist/components/actions/JsonImport.js +68 -61
- package/dist/components/actions/JsonImport.js.map +1 -1
- package/dist/components/actions/JsonImport.module.css +14 -0
- package/dist/components/actions/Move.d.ts.map +1 -1
- package/dist/components/actions/Move.js +41 -0
- package/dist/components/actions/Move.js.map +1 -0
- package/dist/components/actions/Move.module.css +8 -0
- package/dist/components/inputs/InputWrapper.d.ts +1 -1
- package/dist/components/inputs/InputWrapper.d.ts.map +1 -1
- package/dist/components/inputs/InputWrapper.js +31 -29
- package/dist/components/inputs/InputWrapper.js.map +1 -1
- package/dist/components/inputs/InputWrapper.module.css +34 -0
- package/dist/components/inputs/LexicalInput.d.ts +3 -3
- package/dist/components/inputs/LexicalInput.js +86 -0
- package/dist/components/inputs/LexicalInput.js.map +1 -0
- package/dist/components/inputs/MessageInput.d.ts +2 -2
- package/dist/components/inputs/MessageInput.d.ts.map +1 -1
- package/dist/components/inputs/MessageInput.js +110 -37
- package/dist/components/inputs/MessageInput.js.map +1 -1
- package/dist/components/inputs/MessageInput.module.css +25 -0
- package/dist/components/inputs/variables/VariableChip.d.ts +8 -2
- package/dist/components/inputs/variables/VariableChip.d.ts.map +1 -1
- package/dist/components/inputs/variables/VariableChip.js +86 -64
- package/dist/components/inputs/variables/VariableChip.js.map +1 -1
- package/dist/components/inputs/variables/VariableChip.module.css +66 -0
- package/dist/components/inputs/variables/VariableIcon.d.ts +1 -1
- package/dist/components/inputs/variables/VariableIcon.d.ts.map +1 -1
- package/dist/components/inputs/variables/VariableIcon.js +35 -0
- package/dist/components/inputs/variables/VariableIcon.js.map +1 -0
- package/dist/components/inputs/variables/VariableNode.d.ts +11 -0
- package/dist/components/inputs/variables/VariableNode.d.ts.map +1 -0
- package/dist/components/inputs/variables/VariableNode.js +36 -0
- package/dist/components/inputs/variables/VariableNode.js.map +1 -0
- package/dist/components/inputs/variables/VariableSuggestion.module.css +34 -0
- package/dist/components/inputs/variables/editors/DateVariableEditor.d.ts +2 -2
- package/dist/components/inputs/variables/editors/DateVariableEditor.d.ts.map +1 -1
- package/dist/components/inputs/variables/editors/DateVariableEditor.js +15 -0
- package/dist/components/inputs/variables/editors/DateVariableEditor.js.map +1 -0
- package/dist/components/inputs/variables/editors/PluralVariableEditor.d.ts +1 -1
- package/dist/components/inputs/variables/editors/PluralVariableEditor.d.ts.map +1 -1
- package/dist/components/inputs/variables/editors/PluralVariableEditor.js +191 -172
- package/dist/components/inputs/variables/editors/PluralVariableEditor.js.map +1 -1
- package/dist/components/inputs/variables/editors/PluralVariableEditor.module.css +149 -0
- package/dist/components/inputs/variables/editors/SelectVariableEditor.d.ts +1 -1
- package/dist/components/inputs/variables/editors/SelectVariableEditor.d.ts.map +1 -1
- package/dist/components/inputs/variables/editors/SelectVariableEditor.js +58 -52
- package/dist/components/inputs/variables/editors/SelectVariableEditor.js.map +1 -1
- package/dist/components/inputs/variables/editors/SelectVariableEditor.module.css +25 -0
- package/dist/components/inputs/variables/editors/TagVariableEditor.d.ts +1 -1
- package/dist/components/inputs/variables/editors/TagVariableEditor.d.ts.map +1 -1
- package/dist/components/inputs/variables/editors/TagVariableEditor.js +36 -32
- package/dist/components/inputs/variables/editors/TagVariableEditor.js.map +1 -1
- package/dist/components/inputs/variables/editors/TagVariableEditor.module.css +7 -0
- package/dist/components/inputs/variables/editors/TimeVariableEditor.d.ts +2 -2
- package/dist/components/inputs/variables/editors/TimeVariableEditor.d.ts.map +1 -1
- package/dist/components/inputs/variables/editors/TimeVariableEditor.js +15 -0
- package/dist/components/inputs/variables/editors/TimeVariableEditor.js.map +1 -0
- package/dist/components/inputs/variables/pickers/NumericVariablePicker.d.ts +1 -1
- package/dist/components/inputs/variables/pickers/NumericVariablePicker.d.ts.map +1 -1
- package/dist/components/inputs/variables/pickers/NumericVariablePicker.js +48 -51
- package/dist/components/inputs/variables/pickers/NumericVariablePicker.js.map +1 -1
- package/dist/components/inputs/variables/pickers/NumericVariablePicker.module.css +27 -0
- package/dist/components/inputs/variables/pickers/TemporalElementEditor.d.ts +1 -1
- package/dist/components/inputs/variables/pickers/TemporalElementEditor.d.ts.map +1 -1
- package/dist/components/inputs/variables/pickers/TemporalElementEditor.js +58 -0
- package/dist/components/inputs/variables/pickers/TemporalElementEditor.js.map +1 -0
- package/dist/components/inputs/variables/pickers/TemporalElementEditor.module.css +27 -0
- package/dist/components/layout/MessageField.d.ts +3 -3
- package/dist/components/layout/MessageField.d.ts.map +1 -1
- package/dist/components/layout/MessageField.js +56 -56
- package/dist/components/layout/MessageField.js.map +1 -1
- package/dist/components/layout/MessageField.module.css +19 -0
- package/dist/components/layout/MessagesTabs.d.ts +1 -1
- package/dist/components/layout/MessagesTabs.d.ts.map +1 -1
- package/dist/components/layout/MessagesTabs.js +40 -43
- package/dist/components/layout/MessagesTabs.js.map +1 -1
- package/dist/components/layout/MessagesTabs.module.css +21 -0
- package/dist/components/layout/MessagesTree.d.ts +3 -2
- package/dist/components/layout/MessagesTree.d.ts.map +1 -1
- package/dist/components/layout/MessagesTree.js +65 -67
- package/dist/components/layout/MessagesTree.js.map +1 -1
- package/dist/components/layout/MessagesTree.module.css +36 -0
- package/dist/const.d.ts +8 -9
- package/dist/const.d.ts.map +1 -1
- package/dist/const.js +16 -13
- package/dist/const.js.map +1 -1
- package/dist/endpoints/get-messages.d.ts +1 -1
- package/dist/endpoints/get-messages.d.ts.map +1 -1
- package/dist/endpoints/get-messages.js +7 -13
- package/dist/endpoints/get-messages.js.map +1 -1
- package/dist/endpoints/set-messages.d.ts +1 -1
- package/dist/endpoints/set-messages.d.ts.map +1 -1
- package/dist/endpoints/set-messages.js +61 -45
- package/dist/endpoints/set-messages.js.map +1 -1
- package/dist/entities.d.ts +5 -0
- package/dist/entities.d.ts.map +1 -0
- package/dist/entities.js +38 -0
- package/dist/entities.js.map +1 -0
- package/dist/exports/client.d.ts +2 -0
- package/dist/exports/client.d.ts.map +1 -0
- package/dist/exports/client.js +3 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/exports/rsc.d.ts +2 -2
- package/dist/exports/rsc.d.ts.map +1 -1
- package/dist/exports/rsc.js +4 -7
- package/dist/exports/rsc.js.map +1 -1
- package/dist/hooks.d.ts +4 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +24 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +20 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +64 -80
- package/dist/index.js.map +1 -1
- package/dist/payload-types.d.ts +258 -0
- package/dist/payload-types.d.ts.map +1 -0
- package/dist/payload-types.js +15 -0
- package/dist/payload-types.js.map +1 -0
- package/dist/requests/fetchMessageFromAPI.d.ts +10 -0
- package/dist/requests/fetchMessageFromAPI.d.ts.map +1 -0
- package/dist/requests/fetchMessageFromAPI.js +15 -0
- package/dist/requests/fetchMessageFromAPI.js.map +1 -0
- package/dist/requests/fetchMessageFromPayload.d.ts +3 -0
- package/dist/requests/fetchMessageFromPayload.d.ts.map +1 -0
- package/dist/requests/fetchMessageFromPayload.js +29 -0
- package/dist/requests/fetchMessageFromPayload.js.map +1 -0
- package/dist/requests/fetchMessages.d.ts +3 -11
- package/dist/requests/fetchMessages.d.ts.map +1 -1
- package/dist/requests/fetchMessages.js +10 -40
- package/dist/requests/fetchMessages.js.map +1 -1
- package/dist/types.d.ts +7 -23
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/config.d.ts +3 -3
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +27 -17
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/error-handling.js +14 -12
- package/dist/utils/error-handling.js.map +1 -1
- package/dist/utils/format.d.ts +1 -1
- package/dist/utils/format.js +21 -13
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/guards.d.ts +2 -1
- package/dist/utils/guards.js +8 -18
- package/dist/utils/guards.js.map +1 -1
- package/dist/utils/icu-tranform.d.ts +13 -18
- package/dist/utils/icu-tranform.d.ts.map +1 -1
- package/dist/utils/icu-tranform.js +140 -108
- package/dist/utils/icu-tranform.js.map +1 -1
- package/dist/utils/sanitize.d.ts +1 -1
- package/dist/utils/sanitize.js +36 -17
- package/dist/utils/sanitize.js.map +1 -1
- package/dist/utils/schema.d.ts +1 -3
- package/dist/utils/schema.d.ts.map +1 -1
- package/dist/utils/schema.js +42 -34
- package/dist/utils/schema.js.map +1 -1
- package/dist/utils/validate.d.ts +2 -2
- package/dist/utils/validate.js +52 -53
- package/dist/utils/validate.js.map +1 -1
- package/package.json +35 -52
- package/dist/components/inputs/variables/VariableSuggestion.d.ts +0 -9
- package/dist/components/inputs/variables/VariableSuggestion.d.ts.map +0 -1
- package/dist/components/inputs/variables/VariableSuggestion.js +0 -41
- package/dist/components/inputs/variables/VariableSuggestion.js.map +0 -1
- package/dist/components/inputs/variables/extension.d.ts +0 -4
- package/dist/components/inputs/variables/extension.d.ts.map +0 -1
- package/dist/components/inputs/variables/extension.js +0 -93
- package/dist/components/inputs/variables/extension.js.map +0 -1
- package/dist/context/messages-form.d.ts +0 -29
- package/dist/context/messages-form.d.ts.map +0 -1
- package/dist/context/messages-form.js +0 -26
- package/dist/context/messages-form.js.map +0 -1
- package/dist/exports/link.d.ts.map +0 -1
- package/dist/exports/link.js +0 -21
- package/dist/exports/link.js.map +0 -1
- package/dist/exports/view.d.ts +0 -10
- package/dist/exports/view.d.ts.map +0 -1
- package/dist/exports/view.js +0 -53
- package/dist/exports/view.js.map +0 -1
- package/dist/styles.css +0 -1
- package/dist/utils/cn.d.ts +0 -3
- package/dist/utils/cn.d.ts.map +0 -1
- package/dist/utils/cn.js +0 -9
- package/dist/utils/cn.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,267 +1,108 @@
|
|
|
1
1
|
# payload-intl
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Schema-driven internationalization for Payload CMS using ICU MessageFormat.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/payload-intl)
|
|
6
|
+
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- Define message schema in code; edit translations in a rich admin UI
|
|
11
|
-
- Compatible with [next-intl](https://next-intl.dev/) and any ICU consumer
|
|
12
|
-
- Automatic runtime validation of message arguments
|
|
13
|
-
- Autocomplete to quickly insert and configure valid ICU arguments
|
|
14
|
-
- Add optional descriptions to each message so editors understand the context
|
|
15
|
-
- Visual tree & tabbed editor for quick navigation
|
|
16
|
-
<!-- - Support for Rich Text messages -->
|
|
17
|
-
<!-- - Import/export JSON, copy messages between paths -->
|
|
18
|
-
|
|
19
|
-
## Getting Started
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
# pnpm
|
|
23
|
-
pnpm add payload-intl
|
|
24
|
-
# yarn
|
|
25
|
-
yarn add payload-intl
|
|
26
|
-
# npm
|
|
27
|
-
npm install payload-intl
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### 1) Define messages
|
|
31
|
-
|
|
32
|
-
Organize messages in a hierarchical structure using ICU MessageFormat:
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
// messages.ts
|
|
36
|
-
export default {
|
|
37
|
-
UserProfile: {
|
|
38
|
-
title: "Hello {firstName}",
|
|
39
|
-
description:
|
|
40
|
-
"Welcome back, {firstName}! You have {count, plural, =0 {no messages} one {# message} other {# messages}}.",
|
|
41
|
-
status:
|
|
42
|
-
"Your account is {status, select, active {active} inactive {inactive} pending {pending} other {unknown}}.",
|
|
43
|
-
},
|
|
44
|
-
Navigation: {
|
|
45
|
-
home: "Home",
|
|
46
|
-
about: "About",
|
|
47
|
-
},
|
|
48
|
-
} as const;
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
You can also use JSON files, but additional steps are required for type-safe arguments with next-intl. See the [next-intl documentation](https://next-intl.dev/docs/workflows/typescript#messages-arguments) for details.
|
|
52
|
-
|
|
53
|
-
### 2) Configure Payload
|
|
54
|
-
|
|
55
|
-
Add the plugin to your `payload.config.ts`:
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
import { buildConfig } from "payload";
|
|
59
|
-
import { intlPlugin } from "payload-intl";
|
|
8
|
+
## Overview
|
|
60
9
|
|
|
61
|
-
|
|
10
|
+
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.
|
|
62
11
|
|
|
63
|
-
|
|
64
|
-
// the plugin reads locales from this config
|
|
65
|
-
localization: {
|
|
66
|
-
locales: ["en", "de", "fr"],
|
|
67
|
-
defaultLocale: "en",
|
|
68
|
-
},
|
|
69
|
-
plugins: [
|
|
70
|
-
// add the plugin
|
|
71
|
-
intlPlugin({
|
|
72
|
-
schema: messages,
|
|
73
|
-
}),
|
|
74
|
-
// add the "messages" collection to your storage adapter
|
|
75
|
-
],
|
|
76
|
-
});
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### 3) Fetch messages in your app
|
|
80
|
-
|
|
81
|
-
**Node.js:**
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
import config from "@payload-config";
|
|
85
|
-
import { getPayload } from "payload";
|
|
86
|
-
import { fetchMessages } from "payload-intl/requests";
|
|
12
|
+
**Features**
|
|
87
13
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
14
|
+
- **ICU MessageFormat** — variables, plurals, selects, number/date/time formatting, and XML-like tags.
|
|
15
|
+
- **Schema-driven** — define message keys and templates in a typed schema with automatic validation.
|
|
16
|
+
- **Rich editor UI** — message editor with variable chips, autocompletion, and inline ICU element editors.
|
|
17
|
+
- **JSON import** — bulk-import translations from JSON files directly in the admin UI.
|
|
18
|
+
- **Flexible fetching** — works with a Payload instance (server-side) or a config object (client-side API fetch).
|
|
91
19
|
|
|
92
|
-
|
|
20
|
+
## Installation
|
|
93
21
|
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
const messages = await response.json();
|
|
22
|
+
```sh
|
|
23
|
+
pnpm add payload-intl
|
|
97
24
|
```
|
|
98
25
|
|
|
99
|
-
##
|
|
100
|
-
|
|
101
|
-
The `intlPlugin` accepts the following configuration:
|
|
26
|
+
## Usage
|
|
102
27
|
|
|
103
|
-
|
|
104
|
-
| ----------------------- | ------------------------ | ------------------------------------------------------- |
|
|
105
|
-
| `schema` | **Required** | Your messages schema definition |
|
|
106
|
-
| `collectionSlug` | `"messages"` | Custom collection slug |
|
|
107
|
-
| `editorAccess` | Authenticated users only | Access control for editing messages |
|
|
108
|
-
| `hooks` | - | Collection hooks with and additional `afterUpdate` hook |
|
|
109
|
-
| `tabs` | - | Enable tabbed interface |
|
|
110
|
-
|
|
111
|
-
<!-- ## Storage Adapter Requirements
|
|
112
|
-
|
|
113
|
-
The plugin creates a "messages" upload collection that stores translations as JSON files.
|
|
114
|
-
|
|
115
|
-
You must ensure that the storage provider returns the direct URL to the uploaded files and read access is guaranteed. -->
|
|
116
|
-
|
|
117
|
-
<!-- ## Message Schema Definition
|
|
118
|
-
|
|
119
|
-
### Message Descriptions
|
|
120
|
-
|
|
121
|
-
Add context for editors using the syntax `"[Description] message"`:
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
export default {
|
|
125
|
-
UserProfile: {
|
|
126
|
-
title: "[Greeting shown at the top of user profile page] Hello {firstName}",
|
|
127
|
-
description:
|
|
128
|
-
"[Subtitle with user's name and message count] Welcome back, {firstName}! You have {count} new messages.",
|
|
129
|
-
},
|
|
130
|
-
} as const;
|
|
131
|
-
``` -->
|
|
132
|
-
|
|
133
|
-
<!-- ### Rich Text Messages
|
|
134
|
-
|
|
135
|
-
Use `"$RICH$"` as the message value to enable rich text editing. Note that rich text messages do not support ICU arguments.
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
export default {
|
|
139
|
-
Content: {
|
|
140
|
-
welcome: "$RICH$", // Rich text editor will be used
|
|
141
|
-
terms: "$RICH$", // Rich text editor will be used
|
|
142
|
-
},
|
|
143
|
-
} as const;
|
|
144
|
-
``` -->
|
|
145
|
-
|
|
146
|
-
## Example Usage
|
|
147
|
-
|
|
148
|
-
Here's a complete example showing how to integrate payload-intl using next-intl and S3 storage:
|
|
149
|
-
|
|
150
|
-
```typescript
|
|
28
|
+
```ts
|
|
151
29
|
// payload.config.ts
|
|
152
|
-
import {
|
|
153
|
-
import {
|
|
154
|
-
import { buildConfig } from "payload";
|
|
155
|
-
import { intlPlugin } from "payload-intl";
|
|
156
|
-
|
|
157
|
-
import { messages } from "./i18n/messages";
|
|
30
|
+
import { buildConfig } from 'payload';
|
|
31
|
+
import { intlPlugin } from 'payload-intl';
|
|
158
32
|
|
|
159
33
|
export default buildConfig({
|
|
160
34
|
localization: {
|
|
161
|
-
locales: [
|
|
162
|
-
defaultLocale:
|
|
35
|
+
locales: ['en', 'de', 'fr'],
|
|
36
|
+
defaultLocale: 'en',
|
|
163
37
|
},
|
|
38
|
+
// ...
|
|
164
39
|
plugins: [
|
|
165
40
|
intlPlugin({
|
|
166
|
-
schema:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
prefix: "messages", // or anything else you want
|
|
41
|
+
schema: {
|
|
42
|
+
common: {
|
|
43
|
+
greeting: '[Main greeting] Hello {name}!',
|
|
44
|
+
items: '{count, plural, one {# item} other {# items}}',
|
|
45
|
+
},
|
|
46
|
+
auth: {
|
|
47
|
+
login: 'Sign in',
|
|
48
|
+
logout: 'Sign out',
|
|
175
49
|
},
|
|
176
50
|
},
|
|
51
|
+
tabs: true,
|
|
177
52
|
}),
|
|
178
53
|
],
|
|
179
54
|
});
|
|
180
55
|
```
|
|
181
56
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
title: "Hello {firstName}",
|
|
187
|
-
description:
|
|
188
|
-
"Welcome back, {firstName}! You have {count, plural, =0 {no messages} one {# message} other {# messages}}.",
|
|
189
|
-
},
|
|
190
|
-
// ...
|
|
191
|
-
} as const;
|
|
192
|
-
```
|
|
57
|
+
Fetch messages in your application:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { fetchMessages } from 'payload-intl';
|
|
193
61
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
import type messages from "./messages";
|
|
62
|
+
// Server-side — pass the Payload instance directly
|
|
63
|
+
const messages = await fetchMessages(payload, 'en');
|
|
197
64
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
Messages: typeof messages;
|
|
201
|
-
// ...
|
|
202
|
-
}
|
|
203
|
-
}
|
|
65
|
+
// Client-side — pass a config object to fetch from the REST API
|
|
66
|
+
const messages = await fetchMessages({ serverUrl: 'http://localhost:3000' }, 'en');
|
|
204
67
|
```
|
|
205
68
|
|
|
206
|
-
|
|
207
|
-
// i18n/request.ts
|
|
208
|
-
import { getRequestConfig } from "next-intl/server";
|
|
69
|
+
### Options
|
|
209
70
|
|
|
210
|
-
|
|
71
|
+
| Option | Type | Default | Description |
|
|
72
|
+
| --- | --- | --- | --- |
|
|
73
|
+
| `schema` | `MessagesSchema` | — | Required. Nested object defining message keys and ICU templates. Leaf values are ICU MessageFormat strings, optionally prefixed with a `[description]`. |
|
|
74
|
+
| `collectionSlug` | `CollectionSlug` | `'messages'` | Slug of the collection used to store translation files. |
|
|
75
|
+
| `editorAccess` | `(req: PayloadRequest) => boolean \| Promise<boolean>` | `(req) => req.user !== null` | Access control function that determines who can edit messages. |
|
|
76
|
+
| `hooks` | `MessagesHooks` | `{}` | Collection hooks. Extends Payload's collection hooks with an additional `afterUpdate` callback fired when translations are saved. |
|
|
77
|
+
| `tabs` | `boolean` | `false` | When enabled, top-level keys in the schema are rendered as tabs in the admin UI. |
|
|
211
78
|
|
|
212
|
-
|
|
213
|
-
const messages = await fetchCachedMessages(locale);
|
|
79
|
+
## Contributing
|
|
214
80
|
|
|
215
|
-
|
|
216
|
-
locale,
|
|
217
|
-
messages,
|
|
218
|
-
};
|
|
219
|
-
});
|
|
220
|
-
```
|
|
81
|
+
This plugin lives in the [payload-plugins](https://github.com/davincicoding-org/payload-plugins) monorepo.
|
|
221
82
|
|
|
222
|
-
|
|
223
|
-
// server.ts
|
|
224
|
-
"use server";
|
|
83
|
+
### Development
|
|
225
84
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
import { getPayload } from "payload";
|
|
229
|
-
import { fetchMessages } from "payload-intl";
|
|
85
|
+
```sh
|
|
86
|
+
pnpm install
|
|
230
87
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
// Node.js
|
|
234
|
-
const payload = await getPayload({ config });
|
|
235
|
-
return await fetchMessages(payload, locale);
|
|
88
|
+
# watch this plugin for changes
|
|
89
|
+
pnpm --filter payload-intl dev
|
|
236
90
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
`${process.env.PAYLOAD_API_URL}/intl-plugin/en`,
|
|
240
|
-
);
|
|
241
|
-
return await response.json();
|
|
242
|
-
},
|
|
243
|
-
["messages"],
|
|
244
|
-
{
|
|
245
|
-
revalidate: false,
|
|
246
|
-
},
|
|
247
|
-
);
|
|
91
|
+
# run the Payload dev app (in a second terminal)
|
|
92
|
+
pnpm --filter sandbox dev
|
|
248
93
|
```
|
|
249
94
|
|
|
250
|
-
|
|
95
|
+
The `sandbox/` directory is a Next.js + Payload app that imports plugins via `workspace:*` — use it to test changes locally.
|
|
251
96
|
|
|
252
|
-
|
|
253
|
-
# Install dependencies
|
|
254
|
-
pnpm install
|
|
97
|
+
### Code quality
|
|
255
98
|
|
|
256
|
-
|
|
257
|
-
|
|
99
|
+
- **Formatting & linting** — handled by [Biome](https://biomejs.dev/), enforced on commit via husky + lint-staged.
|
|
100
|
+
- **Commits** — must follow [Conventional Commits](https://www.conventionalcommits.org/) with a valid scope (e.g. `fix(payload-intl): ...`).
|
|
101
|
+
- **Changesets** — please include a [changeset](https://github.com/changesets/changesets) in your PR by running `pnpm release`.
|
|
258
102
|
|
|
259
|
-
|
|
260
|
-
pnpm build
|
|
103
|
+
### Issues & PRs
|
|
261
104
|
|
|
262
|
-
|
|
263
|
-
pnpm test
|
|
264
|
-
```
|
|
105
|
+
Bug reports and feature requests are welcome — [open an issue](https://github.com/davincicoding-org/payload-plugins/issues).
|
|
265
106
|
|
|
266
107
|
## License
|
|
267
108
|
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import { TemplateVariable } from '../types';
|
|
2
|
-
import {
|
|
3
|
-
import { MessageValidator } from '../utils/validate';
|
|
1
|
+
import type { Locale, TemplateVariable } from '../types';
|
|
2
|
+
import type { MessageValidator } from '../utils/validate';
|
|
4
3
|
interface MessageControllerProps {
|
|
5
|
-
type: MessageType;
|
|
6
4
|
label?: string;
|
|
7
|
-
locale:
|
|
5
|
+
locale: Locale;
|
|
8
6
|
name: string;
|
|
9
7
|
className?: string;
|
|
10
8
|
variables: TemplateVariable[];
|
|
11
9
|
validate: MessageValidator;
|
|
12
10
|
}
|
|
13
|
-
export declare function MessageController({
|
|
11
|
+
export declare function MessageController({ name, variables, label, locale, validate, className, }: MessageControllerProps): React.ReactNode;
|
|
14
12
|
export {};
|
|
15
13
|
//# sourceMappingURL=MessageController.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageController.d.ts","sourceRoot":"","sources":["../../src/components/MessageController.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"MessageController.d.ts","sourceRoot":"","sources":["../../src/components/MessageController.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAIzD,UAAU,sBAAsB;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,SAAS,EACT,KAAK,EACL,MAAM,EACN,QAAQ,EACR,SAAS,GACV,EAAE,sBAAsB,GAAG,KAAK,CAAC,SAAS,CAyB1C"}
|
|
@@ -1,43 +1,27 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { Controller
|
|
3
|
-
import { useMessagesForm
|
|
4
|
-
import { MessageInput
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
className: l,
|
|
24
|
-
error: a.error,
|
|
25
|
-
label: t,
|
|
26
|
-
lang: s,
|
|
27
|
-
onBlur: r.onBlur,
|
|
28
|
-
onChange: r.onChange,
|
|
29
|
-
value: r.value || "",
|
|
30
|
-
variables: n
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Controller } from 'react-hook-form';
|
|
3
|
+
import { useMessagesForm } from '../components/MessageFormContext';
|
|
4
|
+
import { MessageInput } from './inputs/MessageInput';
|
|
5
|
+
export function MessageController({ name, variables, label, locale, validate, className }) {
|
|
6
|
+
const { control } = useMessagesForm();
|
|
7
|
+
return /*#__PURE__*/ _jsx(Controller, {
|
|
8
|
+
control: control,
|
|
9
|
+
name: name,
|
|
10
|
+
render: ({ field, fieldState })=>/*#__PURE__*/ _jsx(MessageInput, {
|
|
11
|
+
className: className,
|
|
12
|
+
error: fieldState.error,
|
|
13
|
+
label: label,
|
|
14
|
+
lang: locale,
|
|
15
|
+
onBlur: field.onBlur,
|
|
16
|
+
onChange: field.onChange,
|
|
17
|
+
value: field.value || '',
|
|
18
|
+
variables: variables
|
|
19
|
+
}),
|
|
20
|
+
rules: {
|
|
21
|
+
required: true,
|
|
22
|
+
validate
|
|
31
23
|
}
|
|
32
|
-
|
|
33
|
-
rules: {
|
|
34
|
-
required: !0,
|
|
35
|
-
validate: u
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
);
|
|
24
|
+
});
|
|
39
25
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
};
|
|
43
|
-
//# sourceMappingURL=MessageController.js.map
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=MessageController.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../../src/components/MessageController.tsx"],"sourcesContent":["import { Controller } from 'react-hook-form';\nimport { useMessagesForm } from '@/components/MessageFormContext';\nimport type { Locale, TemplateVariable } from '@/types';\nimport type { MessageValidator } from '@/utils/validate';\n\nimport { MessageInput } from './inputs/MessageInput';\n\ninterface MessageControllerProps {\n label?: string;\n locale: Locale;\n name: string;\n className?: string;\n variables: TemplateVariable[];\n validate: MessageValidator;\n}\n\nexport function MessageController({\n name,\n variables,\n label,\n locale,\n validate,\n className,\n}: MessageControllerProps): React.ReactNode {\n const { control } = useMessagesForm();\n\n return (\n <Controller\n control={control}\n name={name}\n render={({ field, fieldState }) => (\n <MessageInput\n className={className}\n error={fieldState.error}\n label={label}\n lang={locale}\n onBlur={field.onBlur}\n onChange={field.onChange}\n value={(field.value as unknown as string) || ''}\n variables={variables}\n />\n )}\n rules={{\n required: true,\n validate,\n }}\n />\n );\n}\n"],"names":["Controller","useMessagesForm","MessageInput","MessageController","name","variables","label","locale","validate","className","control","render","field","fieldState","error","lang","onBlur","onChange","value","rules","required"],"mappings":";AAAA,SAASA,UAAU,QAAQ,kBAAkB;AAC7C,SAASC,eAAe,QAAQ,kCAAkC;AAIlE,SAASC,YAAY,QAAQ,wBAAwB;AAWrD,OAAO,SAASC,kBAAkB,EAChCC,IAAI,EACJC,SAAS,EACTC,KAAK,EACLC,MAAM,EACNC,QAAQ,EACRC,SAAS,EACc;IACvB,MAAM,EAAEC,OAAO,EAAE,GAAGT;IAEpB,qBACE,KAACD;QACCU,SAASA;QACTN,MAAMA;QACNO,QAAQ,CAAC,EAAEC,KAAK,EAAEC,UAAU,EAAE,iBAC5B,KAACX;gBACCO,WAAWA;gBACXK,OAAOD,WAAWC,KAAK;gBACvBR,OAAOA;gBACPS,MAAMR;gBACNS,QAAQJ,MAAMI,MAAM;gBACpBC,UAAUL,MAAMK,QAAQ;gBACxBC,OAAO,AAACN,MAAMM,KAAK,IAA0B;gBAC7Cb,WAAWA;;QAGfc,OAAO;YACLC,UAAU;YACVZ;QACF;;AAGN"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { UseFormReturn } from 'react-hook-form';
|
|
2
|
+
import type { Locale, Messages, Translations } from '../types';
|
|
3
|
+
export type FormValues = Translations<Messages>;
|
|
4
|
+
interface MessagesFormProviderProps {
|
|
5
|
+
locales: Locale[];
|
|
6
|
+
form: UseFormReturn<FormValues>;
|
|
7
|
+
}
|
|
8
|
+
export declare function MessagesFormProvider({ locales, form, children, }: React.PropsWithChildren<MessagesFormProviderProps>): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare const useMessagesForm: () => {
|
|
10
|
+
watch: import("react-hook-form").UseFormWatch<FormValues>;
|
|
11
|
+
getValues: import("react-hook-form").UseFormGetValues<FormValues>;
|
|
12
|
+
getFieldState: import("react-hook-form").UseFormGetFieldState<FormValues>;
|
|
13
|
+
setError: import("react-hook-form").UseFormSetError<FormValues>;
|
|
14
|
+
clearErrors: import("react-hook-form").UseFormClearErrors<FormValues>;
|
|
15
|
+
setValue: import("react-hook-form").UseFormSetValue<FormValues>;
|
|
16
|
+
trigger: import("react-hook-form").UseFormTrigger<FormValues>;
|
|
17
|
+
formState: import("react-hook-form").FormState<FormValues>;
|
|
18
|
+
resetField: import("react-hook-form").UseFormResetField<FormValues>;
|
|
19
|
+
reset: import("react-hook-form").UseFormReset<FormValues>;
|
|
20
|
+
handleSubmit: import("react-hook-form").UseFormHandleSubmit<FormValues, FormValues>;
|
|
21
|
+
unregister: import("react-hook-form").UseFormUnregister<FormValues>;
|
|
22
|
+
control: import("react-hook-form").Control<FormValues, any, FormValues>;
|
|
23
|
+
register: import("react-hook-form").UseFormRegister<FormValues>;
|
|
24
|
+
setFocus: import("react-hook-form").UseFormSetFocus<FormValues>;
|
|
25
|
+
subscribe: import("react-hook-form").UseFormSubscribe<FormValues>;
|
|
26
|
+
locales: Locale[];
|
|
27
|
+
};
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=MessageFormContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageFormContext.d.ts","sourceRoot":"","sources":["../../src/components/MessageFormContext.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE9D,MAAM,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;AAQhD,UAAU,yBAAyB;IACjC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;CACjC;AAED,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,IAAI,EACJ,QAAQ,GACT,EAAE,KAAK,CAAC,iBAAiB,CAAC,yBAAyB,CAAC,2CAMpD;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;aAtBjB,MAAM,EAAE;CA6BlB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, use } from 'react';
|
|
4
|
+
import { FormProvider, useFormContext } from 'react-hook-form';
|
|
5
|
+
const MessagesFormContext = /*#__PURE__*/ createContext({
|
|
6
|
+
locales: [
|
|
7
|
+
'en'
|
|
8
|
+
]
|
|
9
|
+
});
|
|
10
|
+
export function MessagesFormProvider({ locales, form, children }) {
|
|
11
|
+
return /*#__PURE__*/ _jsx(MessagesFormContext, {
|
|
12
|
+
value: {
|
|
13
|
+
locales
|
|
14
|
+
},
|
|
15
|
+
children: /*#__PURE__*/ _jsx(FormProvider, {
|
|
16
|
+
...form,
|
|
17
|
+
children: children
|
|
18
|
+
})
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export const useMessagesForm = ()=>{
|
|
22
|
+
const context = use(MessagesFormContext);
|
|
23
|
+
const form = useFormContext();
|
|
24
|
+
return {
|
|
25
|
+
...context,
|
|
26
|
+
...form
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=MessageFormContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/MessageFormContext.tsx"],"sourcesContent":["'use client';\n\nimport { createContext, use } from 'react';\nimport type { UseFormReturn } from 'react-hook-form';\nimport { FormProvider, useFormContext } from 'react-hook-form';\nimport type { Locale, Messages, Translations } from '@/types';\n\nexport type FormValues = Translations<Messages>;\n\nconst MessagesFormContext = createContext<{\n locales: Locale[];\n}>({\n locales: ['en'],\n});\n\ninterface MessagesFormProviderProps {\n locales: Locale[];\n form: UseFormReturn<FormValues>;\n}\n\nexport function MessagesFormProvider({\n locales,\n form,\n children,\n}: React.PropsWithChildren<MessagesFormProviderProps>) {\n return (\n <MessagesFormContext value={{ locales }}>\n <FormProvider {...form}>{children}</FormProvider>\n </MessagesFormContext>\n );\n}\n\nexport const useMessagesForm = () => {\n const context = use(MessagesFormContext);\n const form = useFormContext<FormValues>();\n return {\n ...context,\n ...form,\n };\n};\n"],"names":["createContext","use","FormProvider","useFormContext","MessagesFormContext","locales","MessagesFormProvider","form","children","value","useMessagesForm","context"],"mappings":"AAAA;;AAEA,SAASA,aAAa,EAAEC,GAAG,QAAQ,QAAQ;AAE3C,SAASC,YAAY,EAAEC,cAAc,QAAQ,kBAAkB;AAK/D,MAAMC,oCAAsBJ,cAEzB;IACDK,SAAS;QAAC;KAAK;AACjB;AAOA,OAAO,SAASC,qBAAqB,EACnCD,OAAO,EACPE,IAAI,EACJC,QAAQ,EAC2C;IACnD,qBACE,KAACJ;QAAoBK,OAAO;YAAEJ;QAAQ;kBACpC,cAAA,KAACH;YAAc,GAAGK,IAAI;sBAAGC;;;AAG/B;AAEA,OAAO,MAAME,kBAAkB;IAC7B,MAAMC,UAAUV,IAAIG;IACpB,MAAMG,OAAOJ;IACb,OAAO;QACL,GAAGQ,OAAO;QACV,GAAGJ,IAAI;IACT;AACF,EAAE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { DeepPartial,
|
|
1
|
+
import type { DeepPartial, Locale, Messages, MessagesSchema, Translations } from '../types';
|
|
2
2
|
interface MessagesFormProps {
|
|
3
|
-
locales:
|
|
3
|
+
locales: Locale[];
|
|
4
4
|
schema: MessagesSchema;
|
|
5
5
|
tabs?: boolean;
|
|
6
6
|
values: Translations<DeepPartial<Messages>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessagesForm.d.ts","sourceRoot":"","sources":["../../src/components/MessagesForm.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,WAAW,EACX,
|
|
1
|
+
{"version":3,"file":"MessagesForm.d.ts","sourceRoot":"","sources":["../../src/components/MessagesForm.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,WAAW,EACX,MAAM,EACN,QAAQ,EACR,cAAc,EACd,YAAY,EACb,MAAM,SAAS,CAAC;AAQjB,UAAU,iBAAiB;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,YAAY,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5C,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,MAAM,EACN,IAAY,EACZ,MAAM,EACN,WAAW,GACZ,EAAE,iBAAiB,GAAG,KAAK,CAAC,SAAS,CAuGrC"}
|