payload-intl 1.1.3 → 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.
Files changed (204) hide show
  1. package/README.md +62 -221
  2. package/dist/components/MessageController.d.ts +4 -6
  3. package/dist/components/MessageController.d.ts.map +1 -1
  4. package/dist/components/MessageController.js +25 -41
  5. package/dist/components/MessageController.js.map +1 -1
  6. package/dist/components/MessageFormContext.d.ts +29 -0
  7. package/dist/components/MessageFormContext.d.ts.map +1 -0
  8. package/dist/components/MessageFormContext.js +30 -0
  9. package/dist/components/MessageFormContext.js.map +1 -0
  10. package/dist/components/MessagesForm.d.ts +2 -2
  11. package/dist/components/MessagesForm.d.ts.map +1 -1
  12. package/dist/components/MessagesForm.js +126 -112
  13. package/dist/components/MessagesForm.js.map +1 -1
  14. package/dist/components/MessagesForm.module.css +41 -0
  15. package/dist/{exports/link.d.ts → components/MessagesLink.d.ts} +3 -3
  16. package/dist/components/MessagesLink.d.ts.map +1 -0
  17. package/dist/components/MessagesLink.js +19 -0
  18. package/dist/components/MessagesLink.js.map +1 -0
  19. package/dist/components/MessagesView.d.ts +10 -0
  20. package/dist/components/MessagesView.d.ts.map +1 -0
  21. package/dist/components/MessagesView.js +48 -0
  22. package/dist/components/MessagesView.js.map +1 -0
  23. package/dist/components/actions/JsonImport.d.ts.map +1 -1
  24. package/dist/components/actions/JsonImport.js +68 -61
  25. package/dist/components/actions/JsonImport.js.map +1 -1
  26. package/dist/components/actions/JsonImport.module.css +14 -0
  27. package/dist/components/actions/Move.d.ts.map +1 -1
  28. package/dist/components/actions/Move.js +41 -0
  29. package/dist/components/actions/Move.js.map +1 -0
  30. package/dist/components/actions/Move.module.css +8 -0
  31. package/dist/components/inputs/InputWrapper.d.ts +1 -1
  32. package/dist/components/inputs/InputWrapper.d.ts.map +1 -1
  33. package/dist/components/inputs/InputWrapper.js +31 -29
  34. package/dist/components/inputs/InputWrapper.js.map +1 -1
  35. package/dist/components/inputs/InputWrapper.module.css +34 -0
  36. package/dist/components/inputs/LexicalInput.d.ts +3 -3
  37. package/dist/components/inputs/LexicalInput.js +86 -0
  38. package/dist/components/inputs/LexicalInput.js.map +1 -0
  39. package/dist/components/inputs/MessageInput.d.ts +2 -2
  40. package/dist/components/inputs/MessageInput.d.ts.map +1 -1
  41. package/dist/components/inputs/MessageInput.js +110 -37
  42. package/dist/components/inputs/MessageInput.js.map +1 -1
  43. package/dist/components/inputs/MessageInput.module.css +25 -0
  44. package/dist/components/inputs/variables/VariableChip.d.ts +8 -2
  45. package/dist/components/inputs/variables/VariableChip.d.ts.map +1 -1
  46. package/dist/components/inputs/variables/VariableChip.js +86 -64
  47. package/dist/components/inputs/variables/VariableChip.js.map +1 -1
  48. package/dist/components/inputs/variables/VariableChip.module.css +66 -0
  49. package/dist/components/inputs/variables/VariableIcon.d.ts +1 -1
  50. package/dist/components/inputs/variables/VariableIcon.d.ts.map +1 -1
  51. package/dist/components/inputs/variables/VariableIcon.js +35 -0
  52. package/dist/components/inputs/variables/VariableIcon.js.map +1 -0
  53. package/dist/components/inputs/variables/VariableNode.d.ts +11 -0
  54. package/dist/components/inputs/variables/VariableNode.d.ts.map +1 -0
  55. package/dist/components/inputs/variables/VariableNode.js +36 -0
  56. package/dist/components/inputs/variables/VariableNode.js.map +1 -0
  57. package/dist/components/inputs/variables/VariableSuggestion.module.css +34 -0
  58. package/dist/components/inputs/variables/editors/DateVariableEditor.d.ts +2 -2
  59. package/dist/components/inputs/variables/editors/DateVariableEditor.d.ts.map +1 -1
  60. package/dist/components/inputs/variables/editors/DateVariableEditor.js +15 -0
  61. package/dist/components/inputs/variables/editors/DateVariableEditor.js.map +1 -0
  62. package/dist/components/inputs/variables/editors/PluralVariableEditor.d.ts +1 -1
  63. package/dist/components/inputs/variables/editors/PluralVariableEditor.d.ts.map +1 -1
  64. package/dist/components/inputs/variables/editors/PluralVariableEditor.js +191 -172
  65. package/dist/components/inputs/variables/editors/PluralVariableEditor.js.map +1 -1
  66. package/dist/components/inputs/variables/editors/PluralVariableEditor.module.css +149 -0
  67. package/dist/components/inputs/variables/editors/SelectVariableEditor.d.ts +1 -1
  68. package/dist/components/inputs/variables/editors/SelectVariableEditor.d.ts.map +1 -1
  69. package/dist/components/inputs/variables/editors/SelectVariableEditor.js +58 -52
  70. package/dist/components/inputs/variables/editors/SelectVariableEditor.js.map +1 -1
  71. package/dist/components/inputs/variables/editors/SelectVariableEditor.module.css +25 -0
  72. package/dist/components/inputs/variables/editors/TagVariableEditor.d.ts +1 -1
  73. package/dist/components/inputs/variables/editors/TagVariableEditor.d.ts.map +1 -1
  74. package/dist/components/inputs/variables/editors/TagVariableEditor.js +36 -32
  75. package/dist/components/inputs/variables/editors/TagVariableEditor.js.map +1 -1
  76. package/dist/components/inputs/variables/editors/TagVariableEditor.module.css +7 -0
  77. package/dist/components/inputs/variables/editors/TimeVariableEditor.d.ts +2 -2
  78. package/dist/components/inputs/variables/editors/TimeVariableEditor.d.ts.map +1 -1
  79. package/dist/components/inputs/variables/editors/TimeVariableEditor.js +15 -0
  80. package/dist/components/inputs/variables/editors/TimeVariableEditor.js.map +1 -0
  81. package/dist/components/inputs/variables/pickers/NumericVariablePicker.d.ts +1 -1
  82. package/dist/components/inputs/variables/pickers/NumericVariablePicker.d.ts.map +1 -1
  83. package/dist/components/inputs/variables/pickers/NumericVariablePicker.js +48 -51
  84. package/dist/components/inputs/variables/pickers/NumericVariablePicker.js.map +1 -1
  85. package/dist/components/inputs/variables/pickers/NumericVariablePicker.module.css +27 -0
  86. package/dist/components/inputs/variables/pickers/TemporalElementEditor.d.ts +1 -1
  87. package/dist/components/inputs/variables/pickers/TemporalElementEditor.d.ts.map +1 -1
  88. package/dist/components/inputs/variables/pickers/TemporalElementEditor.js +58 -0
  89. package/dist/components/inputs/variables/pickers/TemporalElementEditor.js.map +1 -0
  90. package/dist/components/inputs/variables/pickers/TemporalElementEditor.module.css +27 -0
  91. package/dist/components/layout/MessageField.d.ts +3 -3
  92. package/dist/components/layout/MessageField.d.ts.map +1 -1
  93. package/dist/components/layout/MessageField.js +56 -56
  94. package/dist/components/layout/MessageField.js.map +1 -1
  95. package/dist/components/layout/MessageField.module.css +19 -0
  96. package/dist/components/layout/MessagesTabs.d.ts +1 -1
  97. package/dist/components/layout/MessagesTabs.d.ts.map +1 -1
  98. package/dist/components/layout/MessagesTabs.js +40 -43
  99. package/dist/components/layout/MessagesTabs.js.map +1 -1
  100. package/dist/components/layout/MessagesTabs.module.css +21 -0
  101. package/dist/components/layout/MessagesTree.d.ts +3 -2
  102. package/dist/components/layout/MessagesTree.d.ts.map +1 -1
  103. package/dist/components/layout/MessagesTree.js +65 -67
  104. package/dist/components/layout/MessagesTree.js.map +1 -1
  105. package/dist/components/layout/MessagesTree.module.css +36 -0
  106. package/dist/const.d.ts +8 -9
  107. package/dist/const.d.ts.map +1 -1
  108. package/dist/const.js +16 -13
  109. package/dist/const.js.map +1 -1
  110. package/dist/endpoints/get-messages.d.ts +1 -1
  111. package/dist/endpoints/get-messages.d.ts.map +1 -1
  112. package/dist/endpoints/get-messages.js +7 -13
  113. package/dist/endpoints/get-messages.js.map +1 -1
  114. package/dist/endpoints/set-messages.d.ts +1 -1
  115. package/dist/endpoints/set-messages.d.ts.map +1 -1
  116. package/dist/endpoints/set-messages.js +61 -45
  117. package/dist/endpoints/set-messages.js.map +1 -1
  118. package/dist/entities.d.ts +5 -0
  119. package/dist/entities.d.ts.map +1 -0
  120. package/dist/entities.js +38 -0
  121. package/dist/entities.js.map +1 -0
  122. package/dist/exports/client.d.ts +2 -0
  123. package/dist/exports/client.d.ts.map +1 -0
  124. package/dist/exports/client.js +3 -0
  125. package/dist/exports/client.js.map +1 -0
  126. package/dist/exports/rsc.d.ts +2 -2
  127. package/dist/exports/rsc.d.ts.map +1 -1
  128. package/dist/exports/rsc.js +4 -7
  129. package/dist/exports/rsc.js.map +1 -1
  130. package/dist/hooks.d.ts +4 -0
  131. package/dist/hooks.d.ts.map +1 -0
  132. package/dist/hooks.js +24 -0
  133. package/dist/hooks.js.map +1 -0
  134. package/dist/index.d.ts +20 -3
  135. package/dist/index.d.ts.map +1 -1
  136. package/dist/index.js +64 -80
  137. package/dist/index.js.map +1 -1
  138. package/dist/payload-types.d.ts +258 -0
  139. package/dist/payload-types.d.ts.map +1 -0
  140. package/dist/payload-types.js +15 -0
  141. package/dist/payload-types.js.map +1 -0
  142. package/dist/requests/fetchMessageFromAPI.js +14 -12
  143. package/dist/requests/fetchMessageFromAPI.js.map +1 -1
  144. package/dist/requests/fetchMessageFromPayload.d.ts +1 -1
  145. package/dist/requests/fetchMessageFromPayload.js +28 -29
  146. package/dist/requests/fetchMessageFromPayload.js.map +1 -1
  147. package/dist/requests/fetchMessages.d.ts +3 -3
  148. package/dist/requests/fetchMessages.js +10 -12
  149. package/dist/requests/fetchMessages.js.map +1 -1
  150. package/dist/types.d.ts +7 -23
  151. package/dist/types.d.ts.map +1 -1
  152. package/dist/types.js +3 -0
  153. package/dist/types.js.map +1 -0
  154. package/dist/utils/config.d.ts +3 -3
  155. package/dist/utils/config.d.ts.map +1 -1
  156. package/dist/utils/config.js +27 -17
  157. package/dist/utils/config.js.map +1 -1
  158. package/dist/utils/error-handling.js +14 -12
  159. package/dist/utils/error-handling.js.map +1 -1
  160. package/dist/utils/format.d.ts +1 -1
  161. package/dist/utils/format.js +21 -13
  162. package/dist/utils/format.js.map +1 -1
  163. package/dist/utils/guards.d.ts +2 -1
  164. package/dist/utils/guards.js +8 -18
  165. package/dist/utils/guards.js.map +1 -1
  166. package/dist/utils/icu-tranform.d.ts +13 -18
  167. package/dist/utils/icu-tranform.d.ts.map +1 -1
  168. package/dist/utils/icu-tranform.js +140 -108
  169. package/dist/utils/icu-tranform.js.map +1 -1
  170. package/dist/utils/sanitize.d.ts +1 -1
  171. package/dist/utils/sanitize.js +36 -17
  172. package/dist/utils/sanitize.js.map +1 -1
  173. package/dist/utils/schema.d.ts +1 -3
  174. package/dist/utils/schema.d.ts.map +1 -1
  175. package/dist/utils/schema.js +42 -34
  176. package/dist/utils/schema.js.map +1 -1
  177. package/dist/utils/validate.d.ts +2 -2
  178. package/dist/utils/validate.js +52 -53
  179. package/dist/utils/validate.js.map +1 -1
  180. package/package.json +35 -52
  181. package/dist/components/inputs/variables/VariableSuggestion.d.ts +0 -9
  182. package/dist/components/inputs/variables/VariableSuggestion.d.ts.map +0 -1
  183. package/dist/components/inputs/variables/VariableSuggestion.js +0 -41
  184. package/dist/components/inputs/variables/VariableSuggestion.js.map +0 -1
  185. package/dist/components/inputs/variables/extension.d.ts +0 -4
  186. package/dist/components/inputs/variables/extension.d.ts.map +0 -1
  187. package/dist/components/inputs/variables/extension.js +0 -93
  188. package/dist/components/inputs/variables/extension.js.map +0 -1
  189. package/dist/context/messages-form.d.ts +0 -29
  190. package/dist/context/messages-form.d.ts.map +0 -1
  191. package/dist/context/messages-form.js +0 -26
  192. package/dist/context/messages-form.js.map +0 -1
  193. package/dist/exports/link.d.ts.map +0 -1
  194. package/dist/exports/link.js +0 -21
  195. package/dist/exports/link.js.map +0 -1
  196. package/dist/exports/view.d.ts +0 -10
  197. package/dist/exports/view.d.ts.map +0 -1
  198. package/dist/exports/view.js +0 -53
  199. package/dist/exports/view.js.map +0 -1
  200. package/dist/styles.css +0 -1
  201. package/dist/utils/cn.d.ts +0 -3
  202. package/dist/utils/cn.d.ts.map +0 -1
  203. package/dist/utils/cn.js +0 -9
  204. package/dist/utils/cn.js.map +0 -1
package/README.md CHANGED
@@ -1,267 +1,108 @@
1
1
  # payload-intl
2
2
 
3
- **payload-intl** moves translations out of your codebase.
3
+ Schema-driven internationalization for Payload CMS using ICU MessageFormat.
4
4
 
5
- 1. Define message keys (and their arguments) in TypeScript.
6
- 2. Translate them in Payload’s admin panel — no code required.
5
+ [![npm version](https://img.shields.io/npm/v/payload-intl)](https://www.npmjs.com/package/payload-intl)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
7
 
8
- **Features**
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
- import messages from "./messages";
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
- export default buildConfig({
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
- const payload = await getPayload({ config });
89
- const messages = await fetchMessages(payload, "en");
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
- **Edge runtime:**
20
+ ## Installation
93
21
 
94
- ```typescript
95
- const response = await fetch(`${process.env.PAYLOAD_API_URL}/intl-plugin/en`);
96
- const messages = await response.json();
22
+ ```sh
23
+ pnpm add payload-intl
97
24
  ```
98
25
 
99
- ## Plugin Options
100
-
101
- The `intlPlugin` accepts the following configuration:
26
+ ## Usage
102
27
 
103
- | Option | Default | Description |
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 { s3Storage } from "@payloadcms/storage-s3";
153
- import { revalidateTag } from "next/cache";
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: ["en", "de", "fr"],
162
- defaultLocale: "en",
35
+ locales: ['en', 'de', 'fr'],
36
+ defaultLocale: 'en',
163
37
  },
38
+ // ...
164
39
  plugins: [
165
40
  intlPlugin({
166
- schema: messages,
167
- hooks: {
168
- afterUpdate: () => revalidateTag("messages"), // or anything else you want
169
- },
170
- }),
171
- s3Storage({
172
- collections: {
173
- messages: {
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
- ```typescript
183
- // i18n/messages.ts
184
- export const messages = {
185
- UserProfile: {
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
- ```typescript
195
- // i18n/global.ts
196
- import type messages from "./messages";
62
+ // Server-side — pass the Payload instance directly
63
+ const messages = await fetchMessages(payload, 'en');
197
64
 
198
- declare module "next-intl" {
199
- interface AppConfig {
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
- ```typescript
207
- // i18n/request.ts
208
- import { getRequestConfig } from "next-intl/server";
69
+ ### Options
209
70
 
210
- import { fetchCachedMessages } from "./server/messages";
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
- export default getRequestConfig(async ({ locale }) => {
213
- const messages = await fetchCachedMessages(locale);
79
+ ## Contributing
214
80
 
215
- return {
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
- ```typescript
223
- // server.ts
224
- "use server";
83
+ ### Development
225
84
 
226
- import config from "@payload-config";
227
- import { unstable_cache } from "next/cache";
228
- import { getPayload } from "payload";
229
- import { fetchMessages } from "payload-intl";
85
+ ```sh
86
+ pnpm install
230
87
 
231
- export const fetchCachedMessages = unstable_cache(
232
- async (locale: string) => {
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
- // Edge runtime
238
- const response = await fetch(
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
- ## Development
95
+ The `sandbox/` directory is a Next.js + Payload app that imports plugins via `workspace:*` — use it to test changes locally.
251
96
 
252
- ```bash
253
- # Install dependencies
254
- pnpm install
97
+ ### Code quality
255
98
 
256
- # Start development server
257
- pnpm dev
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
- # Build the plugin
260
- pnpm build
103
+ ### Issues & PRs
261
104
 
262
- # Run tests
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 { MessageType } from '../utils/schema';
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: string;
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({ type, name, variables, label, locale, validate, className, }: MessageControllerProps): React.ReactNode;
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,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAIzD,UAAU,sBAAsB;IAC9B,IAAI,EAAE,WAAW,CAAC;IAClB,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,IAAI,EACJ,SAAS,EACT,KAAK,EACL,MAAM,EACN,QAAQ,EACR,SAAS,GACV,EAAE,sBAAsB,GAAG,KAAK,CAAC,SAAS,CAgD1C"}
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 o } from "react/jsx-runtime";
2
- import { Controller as p } from "react-hook-form";
3
- import { useMessagesForm as g } from "../context/messages-form.js";
4
- import { MessageInput as i } from "./inputs/MessageInput.js";
5
- function v({
6
- type: C,
7
- name: e,
8
- variables: n,
9
- label: t,
10
- locale: s,
11
- validate: u,
12
- className: l
13
- }) {
14
- const { control: m } = g();
15
- return /* @__PURE__ */ o(
16
- p,
17
- {
18
- control: m,
19
- name: e,
20
- render: ({ field: r, fieldState: a }) => /* @__PURE__ */ o(
21
- i,
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
- export {
41
- v as MessageController
42
- };
43
- //# sourceMappingURL=MessageController.js.map
26
+
27
+ //# sourceMappingURL=MessageController.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageController.js","sources":["../../src/components/MessageController.tsx"],"sourcesContent":["import { Controller } from 'react-hook-form';\nimport { useMessagesForm } from '@/context/messages-form';\nimport type { TemplateVariable } from '@/types';\nimport type { MessageType } from '@/utils/schema';\nimport type { MessageValidator } from '@/utils/validate';\n\nimport { MessageInput } from './inputs/MessageInput';\n\ninterface MessageControllerProps {\n type: MessageType;\n label?: string;\n locale: string;\n name: string;\n className?: string;\n variables: TemplateVariable[];\n validate: MessageValidator;\n}\n\nexport function MessageController({\n type,\n name,\n variables,\n label,\n locale,\n validate,\n className,\n}: MessageControllerProps): React.ReactNode {\n const { control } = useMessagesForm();\n\n // if (type === \"rich\") {\n // return (\n // <Controller\n // control={control}\n // name={name}\n // render={({ field, fieldState }) => (\n // <LexicalInput\n // className={className}\n // error={fieldState.error}\n // label={label}\n // lang={locale}\n // onChange={field.onChange}\n // onBlur={field.onBlur}\n // value={(field.value as unknown as string) || \"\"}\n // />\n // )}\n // rules={{\n // required: true,\n // }}\n // />\n // );\n // }\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":["MessageController","type","name","variables","label","locale","validate","className","control","useMessagesForm","jsx","Controller","field","fieldState","MessageInput"],"mappings":";;;;AAkBO,SAASA,EAAkB;AAAA,EAChC,MAAAC;AAAA,EACA,MAAAC;AAAA,EACA,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,QAAAC;AAAA,EACA,UAAAC;AAAA,EACA,WAAAC;AACF,GAA4C;AAC1C,QAAM,EAAE,SAAAC,EAAA,IAAYC,EAAA;AAyBpB,SACE,gBAAAC;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,SAAAH;AAAA,MACA,MAAAN;AAAA,MACA,QAAQ,CAAC,EAAE,OAAAU,GAAO,YAAAC,QAChB,gBAAAH;AAAA,QAACI;AAAA,QAAA;AAAA,UACC,WAAAP;AAAA,UACA,OAAOM,EAAW;AAAA,UAClB,OAAAT;AAAA,UACA,MAAMC;AAAA,UACN,QAAQO,EAAM;AAAA,UACd,UAAUA,EAAM;AAAA,UAChB,OAAQA,EAAM,SAA+B;AAAA,UAC7C,WAAAT;AAAA,QAAA;AAAA,MAAA;AAAA,MAGJ,OAAO;AAAA,QACL,UAAU;AAAA,QACV,UAAAG;AAAA,MAAA;AAAA,IACF;AAAA,EAAA;AAGN;"}
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, Locales, Messages, MessagesSchema, Translations } from '../types';
1
+ import type { DeepPartial, Locale, Messages, MessagesSchema, Translations } from '../types';
2
2
  interface MessagesFormProps {
3
- locales: 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,OAAO,EACP,QAAQ,EACR,cAAc,EACd,YAAY,EACb,MAAM,SAAS,CAAC;AAQjB,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,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,CA6GrC"}
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"}