@roxxel/payload-multilang 0.0.5 → 0.0.7

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 (39) hide show
  1. package/README.md +16 -3
  2. package/dist/components/LanguageListToolbar.js +4 -3
  3. package/dist/components/LanguageListToolbar.js.map +1 -1
  4. package/dist/components/LanguageMetabox.js +18 -17
  5. package/dist/components/LanguageMetabox.js.map +1 -1
  6. package/dist/components/TranslationActionsClient.js +16 -14
  7. package/dist/components/TranslationActionsClient.js.map +1 -1
  8. package/dist/components/TranslationColumnCell.js +4 -1
  9. package/dist/components/TranslationColumnCell.js.map +1 -1
  10. package/dist/components/TranslationColumnCellClient.js +16 -7
  11. package/dist/components/TranslationColumnCellClient.js.map +1 -1
  12. package/dist/components/TranslationsTab.js +9 -8
  13. package/dist/components/TranslationsTab.js.map +1 -1
  14. package/dist/constants.d.ts +1 -1
  15. package/dist/constants.js +1 -1
  16. package/dist/constants.js.map +1 -1
  17. package/dist/endpoints/translations.js +4 -6
  18. package/dist/endpoints/translations.js.map +1 -1
  19. package/dist/hooks/translatedCollection.d.ts +2 -1
  20. package/dist/hooks/translatedCollection.js +321 -16
  21. package/dist/hooks/translatedCollection.js.map +1 -1
  22. package/dist/hooks/translatedGlobal.js +5 -1
  23. package/dist/hooks/translatedGlobal.js.map +1 -1
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.js +22 -2
  26. package/dist/index.js.map +1 -1
  27. package/dist/lib/config.js +2 -10
  28. package/dist/lib/config.js.map +1 -1
  29. package/dist/lib/data.d.ts +1 -2
  30. package/dist/lib/data.js +32 -4
  31. package/dist/lib/data.js.map +1 -1
  32. package/dist/translations.d.ts +72 -0
  33. package/dist/translations.js +72 -0
  34. package/dist/translations.js.map +1 -0
  35. package/dist/types.d.ts +0 -19
  36. package/dist/types.js.map +1 -1
  37. package/docs/configuration.md +51 -9
  38. package/docs/usage.md +17 -35
  39. package/package.json +1 -1
@@ -42,7 +42,6 @@ Payload built-in localization must stay disabled. This plugin models translation
42
42
  | `collections` | `Record<string, true \| MultilangCollectionOptions>` | Collection slugs to localize. |
43
43
  | `globals` | `Record<string, true \| MultilangGlobalOptions>` | Global slugs to localize. |
44
44
  | `fieldNames` | `Partial<MultilangFieldNames>` | Optional custom field names used by localized collections. |
45
- | `duplicateExcludeFields` | `string[]` | Extra top-level fields to skip when a new translation duplicates source document data. |
46
45
  | `disabled` | `boolean` | Returns the Payload config unchanged when true. Useful for temporary opt-out in specific environments. |
47
46
 
48
47
  ## Content Model
@@ -59,6 +58,31 @@ Translated collection entries are independent Payload documents. The plugin adds
59
58
 
60
59
  Do not mark content fields as `localized: true` for this plugin model. Put translated text directly on each language document instead.
61
60
 
61
+ ## Admin UI Translations
62
+
63
+ The plugin registers its own admin UI translations for English (`en`) and Ukrainian (`uk`) through Payload `i18n.translations`.
64
+
65
+ Apps can override any plugin string by setting the same translation keys after installing the plugin:
66
+
67
+ ```ts
68
+ export default buildConfig({
69
+ i18n: {
70
+ translations: {
71
+ uk: {
72
+ payloadMultilang: {
73
+ translations: 'Переклади',
74
+ },
75
+ },
76
+ },
77
+ },
78
+ plugins: [
79
+ payloadMultilang({
80
+ languages,
81
+ }),
82
+ ],
83
+ })
84
+ ```
85
+
62
86
  ## Languages
63
87
 
64
88
  ```ts
@@ -117,11 +141,7 @@ Use collection options when you need custom translation behavior.
117
141
  ```ts
118
142
  payloadMultilang({
119
143
  collections: {
120
- posts: {
121
- duplicate: true,
122
- duplicateExcludeFields: ['legacyId'],
123
- synchronizedFields: ['featuredImage', 'author'],
124
- },
144
+ posts: true,
125
145
  },
126
146
  languages,
127
147
  })
@@ -129,10 +149,32 @@ payloadMultilang({
129
149
 
130
150
  | Option | Type | Description |
131
151
  | ------------------------ | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
132
- | `duplicate` | `boolean` | Defaults to `true`. When creating a translation, copy source document fields into the new document. Set to `false` to create empty translation documents by default. |
133
- | `duplicateExcludeFields` | `string[]` | Additional top-level fields to skip during duplication for this collection. |
134
152
  | `fields` | `Partial<MultilangFieldNames>` | Override metadata field names for this collection. |
135
- | `synchronizedFields` | `string[]` | Top-level fields that should stay the same across all translations in a group. |
153
+
154
+ Mark fields that should stay shared across translations directly in the field config:
155
+
156
+ ```ts
157
+ {
158
+ name: 'featuredImage',
159
+ type: 'upload',
160
+ relationTo: 'media',
161
+ custom: {
162
+ multilang: {
163
+ synchronize: true,
164
+ },
165
+ },
166
+ }
167
+ ```
168
+
169
+ `custom.multilang.synchronize: true` can be set on any data field. Scalar fields copy their value to every translation. Container fields are traversed recursively:
170
+
171
+ - `group` synchronizes every child field recursively.
172
+ - `array` and `blocks` synchronize their row or block shell and every child field recursively.
173
+ - `tabs` are not synchronized as values, but fields inside tabs are traversed and can synchronize normally.
174
+
175
+ Use `custom.multilang.synchronizePosition: true` on `array` or `blocks` when only the outer shell should follow the source document. This synchronizes row or block order, plus block type and block name for blocks, while preserving each translation's nested field values.
176
+
177
+ If a container is not marked but a descendant field is marked with `synchronize: true`, existing rows or blocks are matched without changing translation-local row order or membership.
136
178
 
137
179
  ## Globals
138
180
 
package/docs/usage.md CHANGED
@@ -27,6 +27,12 @@ payloadMultilang({
27
27
 
28
28
  Editors can then choose the document language in the sidebar and create or connect translations from the collection list, document sidebar, or `Translations` edit tab.
29
29
 
30
+ ## Synchronized Fields
31
+
32
+ Mark shared fields with `custom.multilang.synchronize: true`. For `group`, `array`, and `blocks`, this synchronizes nested values recursively. `tabs` are only traversed; fields inside tabs can still opt in.
33
+
34
+ Use `custom.multilang.synchronizePosition: true` on `array` or `blocks` to synchronize only the repeatable shell, preserving localized values inside each row or block.
35
+
30
36
  ## App-Level Convenience Helpers
31
37
 
32
38
  Create one app-owned helper module when you want short helper calls in RSCs, route handlers, or other trusted server code.
@@ -236,48 +242,24 @@ await multilang.updateGlobalByLanguage({
236
242
 
237
243
  ## Keep Shared Fields in Sync
238
244
 
239
- Use `synchronizedFields` for top-level fields that should be identical across translations, such as author, featured image, or canonical taxonomy.
240
-
241
- ```ts
242
- payloadMultilang({
243
- collections: {
244
- posts: {
245
- synchronizedFields: ['featuredImage', 'author', 'category'],
246
- },
247
- },
248
- languages,
249
- })
250
- ```
251
-
252
- When an editor changes one of those fields on a saved translation, the plugin updates the same field on the other linked translations.
253
-
254
- ## Create Empty Translations
255
-
256
- By default, creating a translation duplicates compatible top-level source fields. To make new translations start empty:
245
+ Set `custom.multilang.synchronize` on fields that should be identical across translations, such as author, featured image, canonical taxonomy, or a whole nested group.
257
246
 
258
247
  ```ts
259
- payloadMultilang({
260
- collections: {
261
- posts: {
262
- duplicate: false,
248
+ {
249
+ name: 'featuredImage',
250
+ type: 'upload',
251
+ relationTo: 'media',
252
+ custom: {
253
+ multilang: {
254
+ synchronize: true,
263
255
  },
264
256
  },
265
- languages,
266
- })
257
+ }
267
258
  ```
268
259
 
269
- To duplicate most fields but exclude specific ones:
260
+ When an editor changes one of those fields on a saved translation, the plugin updates the same field on the other linked translations. For `group`, `array`, and `blocks`, `synchronize: true` applies recursively to nested fields.
270
261
 
271
- ```ts
272
- payloadMultilang({
273
- collections: {
274
- posts: {
275
- duplicateExcludeFields: ['slug', 'seoTitle', 'seoDescription'],
276
- },
277
- },
278
- languages,
279
- })
280
- ```
262
+ Use `custom.multilang.synchronizePosition: true` on `array` or `blocks` to keep only the repeatable shell aligned while preserving localized values inside each row or block.
281
263
 
282
264
  ## Generate Types
283
265
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roxxel/payload-multilang",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Polylang-style document localization for Payload CMS",
5
5
  "license": "MIT",
6
6
  "repository": {