@roxxel/payload-multilang 0.0.5 → 0.0.6

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 +122 -15
  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 +43 -9
  38. package/docs/usage.md +10 -34
  39. package/package.json +1 -1
package/README.md CHANGED
@@ -23,9 +23,7 @@ export default buildConfig({
23
23
  plugins: [
24
24
  payloadMultilang({
25
25
  collections: {
26
- posts: {
27
- synchronizedFields: ['featuredImage', 'author'],
28
- },
26
+ posts: true,
29
27
  },
30
28
  globals: {
31
29
  'site-settings': {
@@ -54,6 +52,21 @@ export default buildConfig({
54
52
  })
55
53
  ```
56
54
 
55
+ Mark shared fields in the collection field config:
56
+
57
+ ```ts
58
+ {
59
+ name: 'featuredImage',
60
+ type: 'upload',
61
+ relationTo: 'media',
62
+ custom: {
63
+ multilang: {
64
+ synchronize: true,
65
+ },
66
+ },
67
+ }
68
+ ```
69
+
57
70
  In the Payload admin panel, enabled collections get:
58
71
 
59
72
  - a language selector in the document sidebar
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useConfig, useRouteTransition } from '@payloadcms/ui';
3
+ import { useConfig, useRouteTransition, useTranslation } from '@payloadcms/ui';
4
4
  import { usePathname, useRouter, useSearchParams } from 'next/navigation.js';
5
5
  import { useMemo } from 'react';
6
6
  import '../styles/admin.css';
@@ -11,6 +11,7 @@ export const LanguageListToolbar = ({ collectionSlug })=>{
11
11
  const router = useRouter();
12
12
  const searchParams = useSearchParams();
13
13
  const { isTransitioning, startRouteTransition } = useRouteTransition();
14
+ const { t } = useTranslation();
14
15
  const languages = getConfiguredLanguagesFromConfig(config);
15
16
  const fieldNames = useMemo(()=>getCollectionFieldNames({
16
17
  collectionSlug,
@@ -44,14 +45,14 @@ export const LanguageListToolbar = ({ collectionSlug })=>{
44
45
  children: /*#__PURE__*/ _jsx("label", {
45
46
  className: "payload-multilang-toolbar__select",
46
47
  children: /*#__PURE__*/ _jsxs("select", {
47
- "aria-label": "Language",
48
+ "aria-label": t('payloadMultilang:language'),
48
49
  disabled: isTransitioning,
49
50
  onChange: (event)=>handleLanguageChange(event.target.value),
50
51
  value: currentLanguage,
51
52
  children: [
52
53
  /*#__PURE__*/ _jsx("option", {
53
54
  value: "",
54
- children: "All languages"
55
+ children: t('payloadMultilang:allLanguages')
55
56
  }),
56
57
  languages.map((language)=>/*#__PURE__*/ _jsxs("option", {
57
58
  value: language.code,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/LanguageListToolbar.tsx"],"sourcesContent":["'use client'\n\nimport { useConfig, useRouteTransition } from '@payloadcms/ui'\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation.js'\nimport { useMemo } from 'react'\n\nimport '../styles/admin.css'\nimport { getCollectionFieldNames, getConfiguredLanguagesFromConfig } from './config.js'\n\ntype Props = {\n collectionSlug: string\n}\n\nexport const LanguageListToolbar = ({ collectionSlug }: Props) => {\n const { config } = useConfig()\n const pathname = usePathname()\n const router = useRouter()\n const searchParams = useSearchParams()\n const { isTransitioning, startRouteTransition } = useRouteTransition()\n const languages = getConfiguredLanguagesFromConfig(config)\n const fieldNames = useMemo(\n () => getCollectionFieldNames({ collectionSlug, config }),\n [collectionSlug, config],\n )\n const languageParam = `where[${fieldNames.language}][equals]`\n const currentLanguage = searchParams.get(languageParam) || ''\n\n if (!languages.length) {\n return null\n }\n\n const handleLanguageChange = (language: string) => {\n const nextParams = new URLSearchParams(searchParams.toString())\n\n if (language) {\n nextParams.set(languageParam, language)\n } else {\n nextParams.delete(languageParam)\n }\n\n nextParams.set('page', '1')\n\n const query = nextParams.toString()\n const href = query ? `${pathname}?${query}` : pathname\n\n startRouteTransition(() => {\n router.push(href)\n })\n }\n\n return (\n <div className=\"payload-multilang-toolbar\" data-testid=\"multilang-list-toolbar\">\n <label className=\"payload-multilang-toolbar__select\">\n <select\n aria-label=\"Language\"\n disabled={isTransitioning}\n onChange={(event) => handleLanguageChange(event.target.value)}\n value={currentLanguage}\n >\n <option value=\"\">All languages</option>\n {languages.map((language) => (\n <option key={language.code} value={language.code}>\n {language.flagLabel ? `${language.flagLabel} ` : ''}\n {language.name}\n </option>\n ))}\n </select>\n </label>\n </div>\n )\n}\n"],"names":["useConfig","useRouteTransition","usePathname","useRouter","useSearchParams","useMemo","getCollectionFieldNames","getConfiguredLanguagesFromConfig","LanguageListToolbar","collectionSlug","config","pathname","router","searchParams","isTransitioning","startRouteTransition","languages","fieldNames","languageParam","language","currentLanguage","get","length","handleLanguageChange","nextParams","URLSearchParams","toString","set","delete","query","href","push","div","className","data-testid","label","select","aria-label","disabled","onChange","event","target","value","option","map","code","flagLabel","name"],"mappings":"AAAA;;AAEA,SAASA,SAAS,EAAEC,kBAAkB,QAAQ,iBAAgB;AAC9D,SAASC,WAAW,EAAEC,SAAS,EAAEC,eAAe,QAAQ,qBAAoB;AAC5E,SAASC,OAAO,QAAQ,QAAO;AAE/B,OAAO,sBAAqB;AAC5B,SAASC,uBAAuB,EAAEC,gCAAgC,QAAQ,cAAa;AAMvF,OAAO,MAAMC,sBAAsB,CAAC,EAAEC,cAAc,EAAS;IAC3D,MAAM,EAAEC,MAAM,EAAE,GAAGV;IACnB,MAAMW,WAAWT;IACjB,MAAMU,SAAST;IACf,MAAMU,eAAeT;IACrB,MAAM,EAAEU,eAAe,EAAEC,oBAAoB,EAAE,GAAGd;IAClD,MAAMe,YAAYT,iCAAiCG;IACnD,MAAMO,aAAaZ,QACjB,IAAMC,wBAAwB;YAAEG;YAAgBC;QAAO,IACvD;QAACD;QAAgBC;KAAO;IAE1B,MAAMQ,gBAAgB,CAAC,MAAM,EAAED,WAAWE,QAAQ,CAAC,SAAS,CAAC;IAC7D,MAAMC,kBAAkBP,aAAaQ,GAAG,CAACH,kBAAkB;IAE3D,IAAI,CAACF,UAAUM,MAAM,EAAE;QACrB,OAAO;IACT;IAEA,MAAMC,uBAAuB,CAACJ;QAC5B,MAAMK,aAAa,IAAIC,gBAAgBZ,aAAaa,QAAQ;QAE5D,IAAIP,UAAU;YACZK,WAAWG,GAAG,CAACT,eAAeC;QAChC,OAAO;YACLK,WAAWI,MAAM,CAACV;QACpB;QAEAM,WAAWG,GAAG,CAAC,QAAQ;QAEvB,MAAME,QAAQL,WAAWE,QAAQ;QACjC,MAAMI,OAAOD,QAAQ,GAAGlB,SAAS,CAAC,EAAEkB,OAAO,GAAGlB;QAE9CI,qBAAqB;YACnBH,OAAOmB,IAAI,CAACD;QACd;IACF;IAEA,qBACE,KAACE;QAAIC,WAAU;QAA4BC,eAAY;kBACrD,cAAA,KAACC;YAAMF,WAAU;sBACf,cAAA,MAACG;gBACCC,cAAW;gBACXC,UAAUxB;gBACVyB,UAAU,CAACC,QAAUjB,qBAAqBiB,MAAMC,MAAM,CAACC,KAAK;gBAC5DA,OAAOtB;;kCAEP,KAACuB;wBAAOD,OAAM;kCAAG;;oBAChB1B,UAAU4B,GAAG,CAAC,CAACzB,yBACd,MAACwB;4BAA2BD,OAAOvB,SAAS0B,IAAI;;gCAC7C1B,SAAS2B,SAAS,GAAG,GAAG3B,SAAS2B,SAAS,CAAC,CAAC,CAAC,GAAG;gCAChD3B,SAAS4B,IAAI;;2BAFH5B,SAAS0B,IAAI;;;;;AAStC,EAAC"}
1
+ {"version":3,"sources":["../../src/components/LanguageListToolbar.tsx"],"sourcesContent":["'use client'\n\nimport { useConfig, useRouteTransition, useTranslation } from '@payloadcms/ui'\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation.js'\nimport { useMemo } from 'react'\n\nimport '../styles/admin.css'\n\nimport type {\n PayloadMultilangTranslationKey,\n PayloadMultilangTranslations,\n} from '../translations.js'\n\nimport { getCollectionFieldNames, getConfiguredLanguagesFromConfig } from './config.js'\n\ntype Props = {\n collectionSlug: string\n}\n\nexport const LanguageListToolbar = ({ collectionSlug }: Props) => {\n const { config } = useConfig()\n const pathname = usePathname()\n const router = useRouter()\n const searchParams = useSearchParams()\n const { isTransitioning, startRouteTransition } = useRouteTransition()\n const { t } = useTranslation<\n PayloadMultilangTranslations,\n PayloadMultilangTranslationKey\n >()\n const languages = getConfiguredLanguagesFromConfig(config)\n const fieldNames = useMemo(\n () => getCollectionFieldNames({ collectionSlug, config }),\n [collectionSlug, config],\n )\n const languageParam = `where[${fieldNames.language}][equals]`\n const currentLanguage = searchParams.get(languageParam) || ''\n\n if (!languages.length) {\n return null\n }\n\n const handleLanguageChange = (language: string) => {\n const nextParams = new URLSearchParams(searchParams.toString())\n\n if (language) {\n nextParams.set(languageParam, language)\n } else {\n nextParams.delete(languageParam)\n }\n\n nextParams.set('page', '1')\n\n const query = nextParams.toString()\n const href = query ? `${pathname}?${query}` : pathname\n\n startRouteTransition(() => {\n router.push(href)\n })\n }\n\n return (\n <div className=\"payload-multilang-toolbar\" data-testid=\"multilang-list-toolbar\">\n <label className=\"payload-multilang-toolbar__select\">\n <select\n aria-label={t('payloadMultilang:language')}\n disabled={isTransitioning}\n onChange={(event) => handleLanguageChange(event.target.value)}\n value={currentLanguage}\n >\n <option value=\"\">{t('payloadMultilang:allLanguages')}</option>\n {languages.map((language) => (\n <option key={language.code} value={language.code}>\n {language.flagLabel ? `${language.flagLabel} ` : ''}\n {language.name}\n </option>\n ))}\n </select>\n </label>\n </div>\n )\n}\n"],"names":["useConfig","useRouteTransition","useTranslation","usePathname","useRouter","useSearchParams","useMemo","getCollectionFieldNames","getConfiguredLanguagesFromConfig","LanguageListToolbar","collectionSlug","config","pathname","router","searchParams","isTransitioning","startRouteTransition","t","languages","fieldNames","languageParam","language","currentLanguage","get","length","handleLanguageChange","nextParams","URLSearchParams","toString","set","delete","query","href","push","div","className","data-testid","label","select","aria-label","disabled","onChange","event","target","value","option","map","code","flagLabel","name"],"mappings":"AAAA;;AAEA,SAASA,SAAS,EAAEC,kBAAkB,EAAEC,cAAc,QAAQ,iBAAgB;AAC9E,SAASC,WAAW,EAAEC,SAAS,EAAEC,eAAe,QAAQ,qBAAoB;AAC5E,SAASC,OAAO,QAAQ,QAAO;AAE/B,OAAO,sBAAqB;AAO5B,SAASC,uBAAuB,EAAEC,gCAAgC,QAAQ,cAAa;AAMvF,OAAO,MAAMC,sBAAsB,CAAC,EAAEC,cAAc,EAAS;IAC3D,MAAM,EAAEC,MAAM,EAAE,GAAGX;IACnB,MAAMY,WAAWT;IACjB,MAAMU,SAAST;IACf,MAAMU,eAAeT;IACrB,MAAM,EAAEU,eAAe,EAAEC,oBAAoB,EAAE,GAAGf;IAClD,MAAM,EAAEgB,CAAC,EAAE,GAAGf;IAId,MAAMgB,YAAYV,iCAAiCG;IACnD,MAAMQ,aAAab,QACjB,IAAMC,wBAAwB;YAAEG;YAAgBC;QAAO,IACvD;QAACD;QAAgBC;KAAO;IAE1B,MAAMS,gBAAgB,CAAC,MAAM,EAAED,WAAWE,QAAQ,CAAC,SAAS,CAAC;IAC7D,MAAMC,kBAAkBR,aAAaS,GAAG,CAACH,kBAAkB;IAE3D,IAAI,CAACF,UAAUM,MAAM,EAAE;QACrB,OAAO;IACT;IAEA,MAAMC,uBAAuB,CAACJ;QAC5B,MAAMK,aAAa,IAAIC,gBAAgBb,aAAac,QAAQ;QAE5D,IAAIP,UAAU;YACZK,WAAWG,GAAG,CAACT,eAAeC;QAChC,OAAO;YACLK,WAAWI,MAAM,CAACV;QACpB;QAEAM,WAAWG,GAAG,CAAC,QAAQ;QAEvB,MAAME,QAAQL,WAAWE,QAAQ;QACjC,MAAMI,OAAOD,QAAQ,GAAGnB,SAAS,CAAC,EAAEmB,OAAO,GAAGnB;QAE9CI,qBAAqB;YACnBH,OAAOoB,IAAI,CAACD;QACd;IACF;IAEA,qBACE,KAACE;QAAIC,WAAU;QAA4BC,eAAY;kBACrD,cAAA,KAACC;YAAMF,WAAU;sBACf,cAAA,MAACG;gBACCC,cAAYtB,EAAE;gBACduB,UAAUzB;gBACV0B,UAAU,CAACC,QAAUjB,qBAAqBiB,MAAMC,MAAM,CAACC,KAAK;gBAC5DA,OAAOtB;;kCAEP,KAACuB;wBAAOD,OAAM;kCAAI3B,EAAE;;oBACnBC,UAAU4B,GAAG,CAAC,CAACzB,yBACd,MAACwB;4BAA2BD,OAAOvB,SAAS0B,IAAI;;gCAC7C1B,SAAS2B,SAAS,GAAG,GAAG3B,SAAS2B,SAAS,CAAC,CAAC,CAAC,GAAG;gCAChD3B,SAAS4B,IAAI;;2BAFH5B,SAAS0B,IAAI;;;;;AAStC,EAAC"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { toast, useConfig, useDocumentInfo, useField, useRouteTransition } from '@payloadcms/ui';
3
+ import { toast, useConfig, useDocumentInfo, useField, useRouteTransition, useTranslation } from '@payloadcms/ui';
4
4
  import { useRouter } from 'next/navigation.js';
5
5
  import { formatAdminURL } from 'payload/shared';
6
6
  import { useEffect, useMemo, useState } from 'react';
@@ -29,16 +29,13 @@ const PenIcon = ()=>/*#__PURE__*/ _jsxs("svg", {
29
29
  })
30
30
  ]
31
31
  });
32
- const getDocumentID = (doc)=>{
33
- const id = doc?.id;
34
- return typeof id === 'number' || typeof id === 'string' ? id : undefined;
35
- };
36
32
  const isSameDocumentID = (left, right)=>left !== undefined && right !== undefined && String(left) === String(right);
37
33
  export const LanguageMetabox = ()=>{
38
34
  const { config } = useConfig();
39
- const { collectionSlug, id } = useDocumentInfo();
35
+ const { id, collectionSlug } = useDocumentInfo();
40
36
  const router = useRouter();
41
37
  const { isTransitioning, startRouteTransition } = useRouteTransition();
38
+ const { t } = useTranslation();
42
39
  const fieldNames = useMemo(()=>getCollectionFieldNames({
43
40
  collectionSlug,
44
41
  config
@@ -134,7 +131,7 @@ export const LanguageMetabox = ()=>{
134
131
  };
135
132
  const createTranslation = async (targetLanguage)=>{
136
133
  if (!collectionSlug || !docID) {
137
- toast.error('Save the document before creating translations.');
134
+ toast.error(t('payloadMultilang:saveBeforeCreatingTranslations'));
138
135
  return;
139
136
  }
140
137
  setBusyLanguage(targetLanguage);
@@ -155,7 +152,7 @@ export const LanguageMetabox = ()=>{
155
152
  setBusyLanguage(undefined);
156
153
  if (!response.ok) {
157
154
  const result = await response.json().catch(()=>undefined);
158
- toast.error(result?.message || 'Translation could not be created.');
155
+ toast.error(result?.message || t('payloadMultilang:translationCouldNotBeCreated'));
159
156
  return;
160
157
  }
161
158
  const result = await response.json();
@@ -171,14 +168,14 @@ export const LanguageMetabox = ()=>{
171
168
  /*#__PURE__*/ _jsx("div", {
172
169
  className: "payload-multilang-metabox__header",
173
170
  children: /*#__PURE__*/ _jsx("h3", {
174
- children: "Language"
171
+ children: t('payloadMultilang:language')
175
172
  })
176
173
  }),
177
174
  /*#__PURE__*/ _jsxs("label", {
178
175
  className: "payload-multilang-field",
179
176
  children: [
180
177
  /*#__PURE__*/ _jsx("span", {
181
- children: "Language"
178
+ children: t('payloadMultilang:language')
182
179
  }),
183
180
  /*#__PURE__*/ _jsxs("div", {
184
181
  className: "payload-multilang-language-select",
@@ -194,7 +191,7 @@ export const LanguageMetabox = ()=>{
194
191
  children: [
195
192
  /*#__PURE__*/ _jsx("option", {
196
193
  value: "",
197
- children: "Unassigned"
194
+ children: t('payloadMultilang:unassigned')
198
195
  }),
199
196
  languages.map((language)=>{
200
197
  const isCurrent = selectedLanguageCode === language.code;
@@ -220,7 +217,7 @@ export const LanguageMetabox = ()=>{
220
217
  "data-testid": "multilang-sidebar-translations",
221
218
  children: [
222
219
  /*#__PURE__*/ _jsx("h4", {
223
- children: "Translations"
220
+ children: t('payloadMultilang:translations')
224
221
  }),
225
222
  languages.map((language)=>{
226
223
  const translation = translationState?.translations[language.code];
@@ -240,19 +237,23 @@ export const LanguageMetabox = ()=>{
240
237
  }),
241
238
  isCurrent ? /*#__PURE__*/ _jsx("span", {
242
239
  className: "payload-multilang-translation-row__current",
243
- children: "Current"
240
+ children: t('payloadMultilang:current')
244
241
  }) : isUnavailableForCreate ? /*#__PURE__*/ _jsx("span", {
245
242
  className: "payload-multilang-translation-row__current",
246
- children: "Localized"
243
+ children: t('payloadMultilang:localized')
247
244
  }) : translationID ? /*#__PURE__*/ _jsx("button", {
248
- "aria-label": `Edit ${language.name} translation`,
245
+ "aria-label": t('payloadMultilang:editTranslationFor', {
246
+ language: language.name
247
+ }),
249
248
  className: "payload-multilang-link-button",
250
249
  disabled: isTransitioning,
251
250
  onClick: ()=>navigateToTranslation(translationID),
252
251
  type: "button",
253
252
  children: /*#__PURE__*/ _jsx(PenIcon, {})
254
253
  }) : /*#__PURE__*/ _jsx("button", {
255
- "aria-label": `Create ${language.name} translation`,
254
+ "aria-label": t('payloadMultilang:createTranslationFor', {
255
+ language: language.name
256
+ }),
256
257
  className: "payload-multilang-icon-button",
257
258
  disabled: !docID || busyLanguage === language.code || isTransitioning,
258
259
  onClick: ()=>void createTranslation(language.code),
@@ -264,7 +265,7 @@ export const LanguageMetabox = ()=>{
264
265
  }),
265
266
  !docID ? /*#__PURE__*/ _jsx("div", {
266
267
  className: "payload-multilang-muted",
267
- children: "Save before adding translations."
268
+ children: t('payloadMultilang:saveBeforeAddingTranslations')
268
269
  }) : null
269
270
  ]
270
271
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/LanguageMetabox.tsx"],"sourcesContent":["'use client'\n\nimport { toast, useConfig, useDocumentInfo, useField, useRouteTransition } from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation.js'\nimport { formatAdminURL } from 'payload/shared'\nimport { useEffect, useMemo, useState } from 'react'\n\nimport '../styles/admin.css'\nimport type { TranslationState } from '../types.js'\nimport {\n getCollectionFieldNames,\n getConfiguredLanguagesFromConfig,\n getDefaultLanguageFromConfig,\n} from './config.js'\n\nconst PenIcon = () => (\n <svg\n aria-hidden=\"true\"\n className=\"payload-multilang-pen-icon\"\n fill=\"none\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n width=\"16\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M9.9 2.6 13.4 6 5.7 13.7 2.2 14.4 2.9 10.9 9.9 2.6Z\"\n stroke=\"currentColor\"\n strokeLinejoin=\"round\"\n strokeWidth=\"1.4\"\n />\n <path d=\"M8.8 3.9 12.1 7.2\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeWidth=\"1.4\" />\n </svg>\n)\n\nconst getDocumentID = (doc: Record<string, unknown> | undefined): number | string | undefined => {\n const id = doc?.id\n\n return typeof id === 'number' || typeof id === 'string' ? id : undefined\n}\n\nconst isSameDocumentID = (\n left: number | string | undefined,\n right: number | string | undefined,\n): boolean => left !== undefined && right !== undefined && String(left) === String(right)\n\nexport const LanguageMetabox = () => {\n const { config } = useConfig()\n const { collectionSlug, id } = useDocumentInfo()\n const router = useRouter()\n const { isTransitioning, startRouteTransition } = useRouteTransition()\n const fieldNames = useMemo(\n () => getCollectionFieldNames({ collectionSlug, config }),\n [collectionSlug, config],\n )\n const languageField = useField<string>({ path: fieldNames.language })\n const languages = getConfiguredLanguagesFromConfig(config)\n const defaultLanguage = getDefaultLanguageFromConfig(config)\n const [busyLanguage, setBusyLanguage] = useState<string>()\n const [translationState, setTranslationState] = useState<TranslationState>()\n const groupField = useField<string>({ path: fieldNames.group })\n const docID = typeof id === 'number' || typeof id === 'string' ? id : undefined\n const groupValue = groupField.value\n const isCreation = !docID\n const localizedLanguageCodes = useMemo(\n () => new Set(Object.keys(translationState?.translations || {})),\n [translationState?.translations],\n )\n const configuredLanguageCodes = useMemo(\n () => new Set(languages.map((language) => language.code)),\n [languages],\n )\n const availableCreationLanguage = useMemo(\n () => languages.find((language) => !localizedLanguageCodes.has(language.code)),\n [languages, localizedLanguageCodes],\n )\n const preferredCreationLanguage =\n (defaultLanguage && !localizedLanguageCodes.has(defaultLanguage.code)\n ? defaultLanguage\n : availableCreationLanguage\n )?.code || ''\n\n useEffect(() => {\n if (isCreation) {\n if (!preferredCreationLanguage) {\n if (languageField.value && localizedLanguageCodes.has(languageField.value)) {\n languageField.setValue('')\n }\n\n return\n }\n\n if (!languageField.value || localizedLanguageCodes.has(languageField.value)) {\n languageField.setValue(preferredCreationLanguage)\n }\n\n return\n }\n\n if (\n languageField.value &&\n !configuredLanguageCodes.has(languageField.value)\n ) {\n languageField.setValue('')\n }\n }, [\n configuredLanguageCodes,\n isCreation,\n languageField,\n localizedLanguageCodes,\n preferredCreationLanguage,\n ])\n\n useEffect(() => {\n if (!collectionSlug || (!docID && !groupValue)) {\n setTranslationState(undefined)\n return\n }\n\n const loadState = async () => {\n const query = docID\n ? `id=${encodeURIComponent(String(docID))}`\n : `group=${encodeURIComponent(groupValue!)}`\n\n const response = await fetch(\n formatAdminURL({\n apiRoute: config.routes.api,\n path: `/${collectionSlug}/multilang/state?${query}`,\n }),\n {\n credentials: 'include',\n },\n )\n\n if (!response.ok) {\n return\n }\n\n const result = (await response.json()) as TranslationState\n setTranslationState(result)\n }\n\n void loadState()\n }, [collectionSlug, config.routes.api, docID, groupValue])\n\n const selectedLanguageCode = isCreation\n ? languageField.value || preferredCreationLanguage\n : languageField.value && configuredLanguageCodes.has(languageField.value)\n ? languageField.value\n : ''\n const selectedLanguage = languages.find((language) => language.code === selectedLanguageCode)\n const persistedLanguage = !isCreation ? translationState?.language : undefined\n const hasAssignedConfiguredLanguage = Boolean(\n !isCreation &&\n (translationState\n ? persistedLanguage && configuredLanguageCodes.has(persistedLanguage)\n : selectedLanguage),\n )\n\n const collectionAdminURL = (documentID: number | string) =>\n formatAdminURL({\n adminRoute: config.routes.admin,\n path: `/collections/${collectionSlug}/${documentID}`,\n })\n\n const navigateToTranslation = (documentID: number | string) => {\n startRouteTransition(() => {\n router.push(collectionAdminURL(documentID))\n })\n }\n\n const createTranslation = async (targetLanguage: string) => {\n if (!collectionSlug || !docID) {\n toast.error('Save the document before creating translations.')\n return\n }\n\n setBusyLanguage(targetLanguage)\n\n const response = await fetch(\n formatAdminURL({\n apiRoute: config.routes.api,\n path: `/${collectionSlug}/multilang/create`,\n }),\n {\n body: JSON.stringify({\n sourceId: docID,\n targetLanguage,\n }),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n },\n )\n\n setBusyLanguage(undefined)\n\n if (!response.ok) {\n const result = (await response.json().catch(() => undefined)) as\n { message?: string } | undefined\n toast.error(result?.message || 'Translation could not be created.')\n return\n }\n\n const result = (await response.json()) as {\n doc?: { id?: number | string }\n }\n\n if (result.doc?.id) {\n startRouteTransition(() => {\n router.push(collectionAdminURL(result.doc!.id!))\n })\n }\n }\n\n return (\n <section className=\"payload-multilang-metabox\">\n <div className=\"payload-multilang-metabox__header\">\n <h3>Language</h3>\n </div>\n\n <label className=\"payload-multilang-field\">\n <span>Language</span>\n <div className=\"payload-multilang-language-select\">\n <span className=\"payload-multilang-language-select__flag\">\n {selectedLanguage?.flagLabel || '--'}\n </span>\n <select\n disabled={hasAssignedConfiguredLanguage}\n onChange={(event) => languageField.setValue(event.target.value)}\n value={selectedLanguageCode}\n >\n <option value=\"\">Unassigned</option>\n {languages.map((language) => {\n const isCurrent = selectedLanguageCode === language.code\n const isLocalized = localizedLanguageCodes.has(language.code)\n const disabled =\n isCreation || !hasAssignedConfiguredLanguage\n ? isLocalized && !isCurrent\n : true\n\n return (\n <option disabled={disabled} key={language.code} value={language.code}>\n {language.flagLabel ? `${language.flagLabel} ` : ''}\n {language.name}\n </option>\n )\n })}\n </select>\n </div>\n </label>\n\n <div className=\"payload-multilang-translations\" data-testid=\"multilang-sidebar-translations\">\n <h4>Translations</h4>\n {languages.map((language) => {\n const translation = translationState?.translations[language.code]\n const translationID =\n typeof translation?.id === 'number' || typeof translation?.id === 'string'\n ? translation.id\n : undefined\n const isCurrent = isSameDocumentID(translationID, docID)\n const isUnavailableForCreate =\n isCreation && Boolean(translationID) && selectedLanguageCode !== language.code\n\n return (\n <div className=\"payload-multilang-translation-row\" key={language.code}>\n <span className=\"payload-multilang-translation-row__flag\">\n {language.flagLabel || language.code.toUpperCase()}\n </span>\n <span className=\"payload-multilang-translation-row__name\">{language.name}</span>\n {isCurrent ? (\n <span className=\"payload-multilang-translation-row__current\">Current</span>\n ) : isUnavailableForCreate ? (\n <span className=\"payload-multilang-translation-row__current\">Localized</span>\n ) : translationID ? (\n <button\n aria-label={`Edit ${language.name} translation`}\n className=\"payload-multilang-link-button\"\n disabled={isTransitioning}\n onClick={() => navigateToTranslation(translationID)}\n type=\"button\"\n >\n <PenIcon />\n </button>\n ) : (\n <button\n aria-label={`Create ${language.name} translation`}\n className=\"payload-multilang-icon-button\"\n disabled={!docID || busyLanguage === language.code || isTransitioning}\n onClick={() => void createTranslation(language.code)}\n type=\"button\"\n >\n +\n </button>\n )}\n </div>\n )\n })}\n {!docID ? (\n <div className=\"payload-multilang-muted\">Save before adding translations.</div>\n ) : null}\n </div>\n </section>\n )\n}\n"],"names":["toast","useConfig","useDocumentInfo","useField","useRouteTransition","useRouter","formatAdminURL","useEffect","useMemo","useState","getCollectionFieldNames","getConfiguredLanguagesFromConfig","getDefaultLanguageFromConfig","PenIcon","svg","aria-hidden","className","fill","height","viewBox","width","xmlns","path","d","stroke","strokeLinejoin","strokeWidth","strokeLinecap","getDocumentID","doc","id","undefined","isSameDocumentID","left","right","String","LanguageMetabox","config","collectionSlug","router","isTransitioning","startRouteTransition","fieldNames","languageField","language","languages","defaultLanguage","busyLanguage","setBusyLanguage","translationState","setTranslationState","groupField","group","docID","groupValue","value","isCreation","localizedLanguageCodes","Set","Object","keys","translations","configuredLanguageCodes","map","code","availableCreationLanguage","find","has","preferredCreationLanguage","setValue","loadState","query","encodeURIComponent","response","fetch","apiRoute","routes","api","credentials","ok","result","json","selectedLanguageCode","selectedLanguage","persistedLanguage","hasAssignedConfiguredLanguage","Boolean","collectionAdminURL","documentID","adminRoute","admin","navigateToTranslation","push","createTranslation","targetLanguage","error","body","JSON","stringify","sourceId","headers","method","catch","message","section","div","h3","label","span","flagLabel","select","disabled","onChange","event","target","option","isCurrent","isLocalized","name","data-testid","h4","translation","translationID","isUnavailableForCreate","toUpperCase","button","aria-label","onClick","type"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/LanguageMetabox.tsx"],"sourcesContent":["'use client'\n\nimport {\n toast,\n useConfig,\n useDocumentInfo,\n useField,\n useRouteTransition,\n useTranslation,\n} from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation.js'\nimport { formatAdminURL } from 'payload/shared'\nimport { useEffect, useMemo, useState } from 'react'\n\nimport '../styles/admin.css'\n\nimport type {\n PayloadMultilangTranslationKey,\n PayloadMultilangTranslations,\n} from '../translations.js'\nimport type { TranslationState } from '../types.js'\n\nimport {\n getCollectionFieldNames,\n getConfiguredLanguagesFromConfig,\n getDefaultLanguageFromConfig,\n} from './config.js'\n\nconst PenIcon = () => (\n <svg\n aria-hidden=\"true\"\n className=\"payload-multilang-pen-icon\"\n fill=\"none\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n width=\"16\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M9.9 2.6 13.4 6 5.7 13.7 2.2 14.4 2.9 10.9 9.9 2.6Z\"\n stroke=\"currentColor\"\n strokeLinejoin=\"round\"\n strokeWidth=\"1.4\"\n />\n <path d=\"M8.8 3.9 12.1 7.2\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeWidth=\"1.4\" />\n </svg>\n)\n\nconst isSameDocumentID = (\n left: number | string | undefined,\n right: number | string | undefined,\n): boolean => left !== undefined && right !== undefined && String(left) === String(right)\n\nexport const LanguageMetabox = () => {\n const { config } = useConfig()\n const { id, collectionSlug } = useDocumentInfo()\n const router = useRouter()\n const { isTransitioning, startRouteTransition } = useRouteTransition()\n const { t } = useTranslation<\n PayloadMultilangTranslations,\n PayloadMultilangTranslationKey\n >()\n const fieldNames = useMemo(\n () => getCollectionFieldNames({ collectionSlug, config }),\n [collectionSlug, config],\n )\n const languageField = useField<string>({ path: fieldNames.language })\n const languages = getConfiguredLanguagesFromConfig(config)\n const defaultLanguage = getDefaultLanguageFromConfig(config)\n const [busyLanguage, setBusyLanguage] = useState<string>()\n const [translationState, setTranslationState] = useState<TranslationState>()\n const groupField = useField<string>({ path: fieldNames.group })\n const docID = typeof id === 'number' || typeof id === 'string' ? id : undefined\n const groupValue = groupField.value\n const isCreation = !docID\n const localizedLanguageCodes = useMemo(\n () => new Set(Object.keys(translationState?.translations || {})),\n [translationState?.translations],\n )\n const configuredLanguageCodes = useMemo(\n () => new Set(languages.map((language) => language.code)),\n [languages],\n )\n const availableCreationLanguage = useMemo(\n () => languages.find((language) => !localizedLanguageCodes.has(language.code)),\n [languages, localizedLanguageCodes],\n )\n const preferredCreationLanguage =\n (defaultLanguage && !localizedLanguageCodes.has(defaultLanguage.code)\n ? defaultLanguage\n : availableCreationLanguage\n )?.code || ''\n\n useEffect(() => {\n if (isCreation) {\n if (!preferredCreationLanguage) {\n if (languageField.value && localizedLanguageCodes.has(languageField.value)) {\n languageField.setValue('')\n }\n\n return\n }\n\n if (!languageField.value || localizedLanguageCodes.has(languageField.value)) {\n languageField.setValue(preferredCreationLanguage)\n }\n\n return\n }\n\n if (\n languageField.value &&\n !configuredLanguageCodes.has(languageField.value)\n ) {\n languageField.setValue('')\n }\n }, [\n configuredLanguageCodes,\n isCreation,\n languageField,\n localizedLanguageCodes,\n preferredCreationLanguage,\n ])\n\n useEffect(() => {\n if (!collectionSlug || (!docID && !groupValue)) {\n setTranslationState(undefined)\n return\n }\n\n const loadState = async () => {\n const query = docID\n ? `id=${encodeURIComponent(String(docID))}`\n : `group=${encodeURIComponent(groupValue)}`\n\n const response = await fetch(\n formatAdminURL({\n apiRoute: config.routes.api,\n path: `/${collectionSlug}/multilang/state?${query}`,\n }),\n {\n credentials: 'include',\n },\n )\n\n if (!response.ok) {\n return\n }\n\n const result = (await response.json()) as TranslationState\n setTranslationState(result)\n }\n\n void loadState()\n }, [collectionSlug, config.routes.api, docID, groupValue])\n\n const selectedLanguageCode = isCreation\n ? languageField.value || preferredCreationLanguage\n : languageField.value && configuredLanguageCodes.has(languageField.value)\n ? languageField.value\n : ''\n const selectedLanguage = languages.find((language) => language.code === selectedLanguageCode)\n const persistedLanguage = !isCreation ? translationState?.language : undefined\n const hasAssignedConfiguredLanguage = Boolean(\n !isCreation &&\n (translationState\n ? persistedLanguage && configuredLanguageCodes.has(persistedLanguage)\n : selectedLanguage),\n )\n\n const collectionAdminURL = (documentID: number | string) =>\n formatAdminURL({\n adminRoute: config.routes.admin,\n path: `/collections/${collectionSlug}/${documentID}`,\n })\n\n const navigateToTranslation = (documentID: number | string) => {\n startRouteTransition(() => {\n router.push(collectionAdminURL(documentID))\n })\n }\n\n const createTranslation = async (targetLanguage: string) => {\n if (!collectionSlug || !docID) {\n toast.error(t('payloadMultilang:saveBeforeCreatingTranslations'))\n return\n }\n\n setBusyLanguage(targetLanguage)\n\n const response = await fetch(\n formatAdminURL({\n apiRoute: config.routes.api,\n path: `/${collectionSlug}/multilang/create`,\n }),\n {\n body: JSON.stringify({\n sourceId: docID,\n targetLanguage,\n }),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n },\n )\n\n setBusyLanguage(undefined)\n\n if (!response.ok) {\n const result = (await response.json().catch(() => undefined)) as\n { message?: string } | undefined\n toast.error(result?.message || t('payloadMultilang:translationCouldNotBeCreated'))\n return\n }\n\n const result = (await response.json()) as {\n doc?: { id?: number | string }\n }\n\n if (result.doc?.id) {\n startRouteTransition(() => {\n router.push(collectionAdminURL(result.doc!.id!))\n })\n }\n }\n\n return (\n <section className=\"payload-multilang-metabox\">\n <div className=\"payload-multilang-metabox__header\">\n <h3>{t('payloadMultilang:language')}</h3>\n </div>\n\n <label className=\"payload-multilang-field\">\n <span>{t('payloadMultilang:language')}</span>\n <div className=\"payload-multilang-language-select\">\n <span className=\"payload-multilang-language-select__flag\">\n {selectedLanguage?.flagLabel || '--'}\n </span>\n <select\n disabled={hasAssignedConfiguredLanguage}\n onChange={(event) => languageField.setValue(event.target.value)}\n value={selectedLanguageCode}\n >\n <option value=\"\">{t('payloadMultilang:unassigned')}</option>\n {languages.map((language) => {\n const isCurrent = selectedLanguageCode === language.code\n const isLocalized = localizedLanguageCodes.has(language.code)\n const disabled =\n isCreation || !hasAssignedConfiguredLanguage\n ? isLocalized && !isCurrent\n : true\n\n return (\n <option disabled={disabled} key={language.code} value={language.code}>\n {language.flagLabel ? `${language.flagLabel} ` : ''}\n {language.name}\n </option>\n )\n })}\n </select>\n </div>\n </label>\n\n <div className=\"payload-multilang-translations\" data-testid=\"multilang-sidebar-translations\">\n <h4>{t('payloadMultilang:translations')}</h4>\n {languages.map((language) => {\n const translation = translationState?.translations[language.code]\n const translationID =\n typeof translation?.id === 'number' || typeof translation?.id === 'string'\n ? translation.id\n : undefined\n const isCurrent = isSameDocumentID(translationID, docID)\n const isUnavailableForCreate =\n isCreation && Boolean(translationID) && selectedLanguageCode !== language.code\n\n return (\n <div className=\"payload-multilang-translation-row\" key={language.code}>\n <span className=\"payload-multilang-translation-row__flag\">\n {language.flagLabel || language.code.toUpperCase()}\n </span>\n <span className=\"payload-multilang-translation-row__name\">{language.name}</span>\n {isCurrent ? (\n <span className=\"payload-multilang-translation-row__current\">\n {t('payloadMultilang:current')}\n </span>\n ) : isUnavailableForCreate ? (\n <span className=\"payload-multilang-translation-row__current\">\n {t('payloadMultilang:localized')}\n </span>\n ) : translationID ? (\n <button\n aria-label={t('payloadMultilang:editTranslationFor', {\n language: language.name,\n })}\n className=\"payload-multilang-link-button\"\n disabled={isTransitioning}\n onClick={() => navigateToTranslation(translationID)}\n type=\"button\"\n >\n <PenIcon />\n </button>\n ) : (\n <button\n aria-label={t('payloadMultilang:createTranslationFor', {\n language: language.name,\n })}\n className=\"payload-multilang-icon-button\"\n disabled={!docID || busyLanguage === language.code || isTransitioning}\n onClick={() => void createTranslation(language.code)}\n type=\"button\"\n >\n +\n </button>\n )}\n </div>\n )\n })}\n {!docID ? (\n <div className=\"payload-multilang-muted\">\n {t('payloadMultilang:saveBeforeAddingTranslations')}\n </div>\n ) : null}\n </div>\n </section>\n )\n}\n"],"names":["toast","useConfig","useDocumentInfo","useField","useRouteTransition","useTranslation","useRouter","formatAdminURL","useEffect","useMemo","useState","getCollectionFieldNames","getConfiguredLanguagesFromConfig","getDefaultLanguageFromConfig","PenIcon","svg","aria-hidden","className","fill","height","viewBox","width","xmlns","path","d","stroke","strokeLinejoin","strokeWidth","strokeLinecap","isSameDocumentID","left","right","undefined","String","LanguageMetabox","config","id","collectionSlug","router","isTransitioning","startRouteTransition","t","fieldNames","languageField","language","languages","defaultLanguage","busyLanguage","setBusyLanguage","translationState","setTranslationState","groupField","group","docID","groupValue","value","isCreation","localizedLanguageCodes","Set","Object","keys","translations","configuredLanguageCodes","map","code","availableCreationLanguage","find","has","preferredCreationLanguage","setValue","loadState","query","encodeURIComponent","response","fetch","apiRoute","routes","api","credentials","ok","result","json","selectedLanguageCode","selectedLanguage","persistedLanguage","hasAssignedConfiguredLanguage","Boolean","collectionAdminURL","documentID","adminRoute","admin","navigateToTranslation","push","createTranslation","targetLanguage","error","body","JSON","stringify","sourceId","headers","method","catch","message","doc","section","div","h3","label","span","flagLabel","select","disabled","onChange","event","target","option","isCurrent","isLocalized","name","data-testid","h4","translation","translationID","isUnavailableForCreate","toUpperCase","button","aria-label","onClick","type"],"mappings":"AAAA;;AAEA,SACEA,KAAK,EACLC,SAAS,EACTC,eAAe,EACfC,QAAQ,EACRC,kBAAkB,EAClBC,cAAc,QACT,iBAAgB;AACvB,SAASC,SAAS,QAAQ,qBAAoB;AAC9C,SAASC,cAAc,QAAQ,iBAAgB;AAC/C,SAASC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AAEpD,OAAO,sBAAqB;AAQ5B,SACEC,uBAAuB,EACvBC,gCAAgC,EAChCC,4BAA4B,QACvB,cAAa;AAEpB,MAAMC,UAAU,kBACd,MAACC;QACCC,eAAY;QACZC,WAAU;QACVC,MAAK;QACLC,QAAO;QACPC,SAAQ;QACRC,OAAM;QACNC,OAAM;;0BAEN,KAACC;gBACCC,GAAE;gBACFC,QAAO;gBACPC,gBAAe;gBACfC,aAAY;;0BAEd,KAACJ;gBAAKC,GAAE;gBAAoBC,QAAO;gBAAeG,eAAc;gBAAQD,aAAY;;;;AAIxF,MAAME,mBAAmB,CACvBC,MACAC,QACYD,SAASE,aAAaD,UAAUC,aAAaC,OAAOH,UAAUG,OAAOF;AAEnF,OAAO,MAAMG,kBAAkB;IAC7B,MAAM,EAAEC,MAAM,EAAE,GAAGlC;IACnB,MAAM,EAAEmC,EAAE,EAAEC,cAAc,EAAE,GAAGnC;IAC/B,MAAMoC,SAAShC;IACf,MAAM,EAAEiC,eAAe,EAAEC,oBAAoB,EAAE,GAAGpC;IAClD,MAAM,EAAEqC,CAAC,EAAE,GAAGpC;IAId,MAAMqC,aAAajC,QACjB,IAAME,wBAAwB;YAAE0B;YAAgBF;QAAO,IACvD;QAACE;QAAgBF;KAAO;IAE1B,MAAMQ,gBAAgBxC,SAAiB;QAAEoB,MAAMmB,WAAWE,QAAQ;IAAC;IACnE,MAAMC,YAAYjC,iCAAiCuB;IACnD,MAAMW,kBAAkBjC,6BAA6BsB;IACrD,MAAM,CAACY,cAAcC,gBAAgB,GAAGtC;IACxC,MAAM,CAACuC,kBAAkBC,oBAAoB,GAAGxC;IAChD,MAAMyC,aAAahD,SAAiB;QAAEoB,MAAMmB,WAAWU,KAAK;IAAC;IAC7D,MAAMC,QAAQ,OAAOjB,OAAO,YAAY,OAAOA,OAAO,WAAWA,KAAKJ;IACtE,MAAMsB,aAAaH,WAAWI,KAAK;IACnC,MAAMC,aAAa,CAACH;IACpB,MAAMI,yBAAyBhD,QAC7B,IAAM,IAAIiD,IAAIC,OAAOC,IAAI,CAACX,kBAAkBY,gBAAgB,CAAC,KAC7D;QAACZ,kBAAkBY;KAAa;IAElC,MAAMC,0BAA0BrD,QAC9B,IAAM,IAAIiD,IAAIb,UAAUkB,GAAG,CAAC,CAACnB,WAAaA,SAASoB,IAAI,IACvD;QAACnB;KAAU;IAEb,MAAMoB,4BAA4BxD,QAChC,IAAMoC,UAAUqB,IAAI,CAAC,CAACtB,WAAa,CAACa,uBAAuBU,GAAG,CAACvB,SAASoB,IAAI,IAC5E;QAACnB;QAAWY;KAAuB;IAErC,MAAMW,4BACJ,AAACtB,CAAAA,mBAAmB,CAACW,uBAAuBU,GAAG,CAACrB,gBAAgBkB,IAAI,IAChElB,kBACAmB,yBAAwB,GACzBD,QAAQ;IAEbxD,UAAU;QACR,IAAIgD,YAAY;YACd,IAAI,CAACY,2BAA2B;gBAC9B,IAAIzB,cAAcY,KAAK,IAAIE,uBAAuBU,GAAG,CAACxB,cAAcY,KAAK,GAAG;oBAC1EZ,cAAc0B,QAAQ,CAAC;gBACzB;gBAEA;YACF;YAEA,IAAI,CAAC1B,cAAcY,KAAK,IAAIE,uBAAuBU,GAAG,CAACxB,cAAcY,KAAK,GAAG;gBAC3EZ,cAAc0B,QAAQ,CAACD;YACzB;YAEA;QACF;QAEA,IACEzB,cAAcY,KAAK,IACnB,CAACO,wBAAwBK,GAAG,CAACxB,cAAcY,KAAK,GAChD;YACAZ,cAAc0B,QAAQ,CAAC;QACzB;IACF,GAAG;QACDP;QACAN;QACAb;QACAc;QACAW;KACD;IAED5D,UAAU;QACR,IAAI,CAAC6B,kBAAmB,CAACgB,SAAS,CAACC,YAAa;YAC9CJ,oBAAoBlB;YACpB;QACF;QAEA,MAAMsC,YAAY;YAChB,MAAMC,QAAQlB,QACV,CAAC,GAAG,EAAEmB,mBAAmBvC,OAAOoB,SAAS,GACzC,CAAC,MAAM,EAAEmB,mBAAmBlB,aAAa;YAE7C,MAAMmB,WAAW,MAAMC,MACrBnE,eAAe;gBACboE,UAAUxC,OAAOyC,MAAM,CAACC,GAAG;gBAC3BtD,MAAM,CAAC,CAAC,EAAEc,eAAe,iBAAiB,EAAEkC,OAAO;YACrD,IACA;gBACEO,aAAa;YACf;YAGF,IAAI,CAACL,SAASM,EAAE,EAAE;gBAChB;YACF;YAEA,MAAMC,SAAU,MAAMP,SAASQ,IAAI;YACnC/B,oBAAoB8B;QACtB;QAEA,KAAKV;IACP,GAAG;QAACjC;QAAgBF,OAAOyC,MAAM,CAACC,GAAG;QAAExB;QAAOC;KAAW;IAEzD,MAAM4B,uBAAuB1B,aACzBb,cAAcY,KAAK,IAAIa,4BACvBzB,cAAcY,KAAK,IAAIO,wBAAwBK,GAAG,CAACxB,cAAcY,KAAK,IACpEZ,cAAcY,KAAK,GACnB;IACN,MAAM4B,mBAAmBtC,UAAUqB,IAAI,CAAC,CAACtB,WAAaA,SAASoB,IAAI,KAAKkB;IACxE,MAAME,oBAAoB,CAAC5B,aAAaP,kBAAkBL,WAAWZ;IACrE,MAAMqD,gCAAgCC,QACpC,CAAC9B,cACEP,CAAAA,mBACGmC,qBAAqBtB,wBAAwBK,GAAG,CAACiB,qBACjDD,gBAAe;IAGvB,MAAMI,qBAAqB,CAACC,aAC1BjF,eAAe;YACbkF,YAAYtD,OAAOyC,MAAM,CAACc,KAAK;YAC/BnE,MAAM,CAAC,aAAa,EAAEc,eAAe,CAAC,EAAEmD,YAAY;QACtD;IAEF,MAAMG,wBAAwB,CAACH;QAC7BhD,qBAAqB;YACnBF,OAAOsD,IAAI,CAACL,mBAAmBC;QACjC;IACF;IAEA,MAAMK,oBAAoB,OAAOC;QAC/B,IAAI,CAACzD,kBAAkB,CAACgB,OAAO;YAC7BrD,MAAM+F,KAAK,CAACtD,EAAE;YACd;QACF;QAEAO,gBAAgB8C;QAEhB,MAAMrB,WAAW,MAAMC,MACrBnE,eAAe;YACboE,UAAUxC,OAAOyC,MAAM,CAACC,GAAG;YAC3BtD,MAAM,CAAC,CAAC,EAAEc,eAAe,iBAAiB,CAAC;QAC7C,IACA;YACE2D,MAAMC,KAAKC,SAAS,CAAC;gBACnBC,UAAU9C;gBACVyC;YACF;YACAhB,aAAa;YACbsB,SAAS;gBACP,gBAAgB;YAClB;YACAC,QAAQ;QACV;QAGFrD,gBAAgBhB;QAEhB,IAAI,CAACyC,SAASM,EAAE,EAAE;YAChB,MAAMC,SAAU,MAAMP,SAASQ,IAAI,GAAGqB,KAAK,CAAC,IAAMtE;YAElDhC,MAAM+F,KAAK,CAACf,QAAQuB,WAAW9D,EAAE;YACjC;QACF;QAEA,MAAMuC,SAAU,MAAMP,SAASQ,IAAI;QAInC,IAAID,OAAOwB,GAAG,EAAEpE,IAAI;YAClBI,qBAAqB;gBACnBF,OAAOsD,IAAI,CAACL,mBAAmBP,OAAOwB,GAAG,CAAEpE,EAAE;YAC/C;QACF;IACF;IAEA,qBACE,MAACqE;QAAQxF,WAAU;;0BACjB,KAACyF;gBAAIzF,WAAU;0BACb,cAAA,KAAC0F;8BAAIlE,EAAE;;;0BAGT,MAACmE;gBAAM3F,WAAU;;kCACf,KAAC4F;kCAAMpE,EAAE;;kCACT,MAACiE;wBAAIzF,WAAU;;0CACb,KAAC4F;gCAAK5F,WAAU;0CACbkE,kBAAkB2B,aAAa;;0CAElC,MAACC;gCACCC,UAAU3B;gCACV4B,UAAU,CAACC,QAAUvE,cAAc0B,QAAQ,CAAC6C,MAAMC,MAAM,CAAC5D,KAAK;gCAC9DA,OAAO2B;;kDAEP,KAACkC;wCAAO7D,OAAM;kDAAId,EAAE;;oCACnBI,UAAUkB,GAAG,CAAC,CAACnB;wCACd,MAAMyE,YAAYnC,yBAAyBtC,SAASoB,IAAI;wCACxD,MAAMsD,cAAc7D,uBAAuBU,GAAG,CAACvB,SAASoB,IAAI;wCAC5D,MAAMgD,WACJxD,cAAc,CAAC6B,gCACXiC,eAAe,CAACD,YAChB;wCAEN,qBACE,MAACD;4CAAOJ,UAAUA;4CAA8BzD,OAAOX,SAASoB,IAAI;;gDACjEpB,SAASkE,SAAS,GAAG,GAAGlE,SAASkE,SAAS,CAAC,CAAC,CAAC,GAAG;gDAChDlE,SAAS2E,IAAI;;2CAFiB3E,SAASoB,IAAI;oCAKlD;;;;;;;0BAKN,MAAC0C;gBAAIzF,WAAU;gBAAiCuG,eAAY;;kCAC1D,KAACC;kCAAIhF,EAAE;;oBACNI,UAAUkB,GAAG,CAAC,CAACnB;wBACd,MAAM8E,cAAczE,kBAAkBY,YAAY,CAACjB,SAASoB,IAAI,CAAC;wBACjE,MAAM2D,gBACJ,OAAOD,aAAatF,OAAO,YAAY,OAAOsF,aAAatF,OAAO,WAC9DsF,YAAYtF,EAAE,GACdJ;wBACN,MAAMqF,YAAYxF,iBAAiB8F,eAAetE;wBAClD,MAAMuE,yBACJpE,cAAc8B,QAAQqC,kBAAkBzC,yBAAyBtC,SAASoB,IAAI;wBAEhF,qBACE,MAAC0C;4BAAIzF,WAAU;;8CACb,KAAC4F;oCAAK5F,WAAU;8CACb2B,SAASkE,SAAS,IAAIlE,SAASoB,IAAI,CAAC6D,WAAW;;8CAElD,KAAChB;oCAAK5F,WAAU;8CAA2C2B,SAAS2E,IAAI;;gCACvEF,0BACC,KAACR;oCAAK5F,WAAU;8CACbwB,EAAE;qCAEHmF,uCACF,KAACf;oCAAK5F,WAAU;8CACbwB,EAAE;qCAEHkF,8BACF,KAACG;oCACCC,cAAYtF,EAAE,uCAAuC;wCACnDG,UAAUA,SAAS2E,IAAI;oCACzB;oCACAtG,WAAU;oCACV+F,UAAUzE;oCACVyF,SAAS,IAAMrC,sBAAsBgC;oCACrCM,MAAK;8CAEL,cAAA,KAACnH;mDAGH,KAACgH;oCACCC,cAAYtF,EAAE,yCAAyC;wCACrDG,UAAUA,SAAS2E,IAAI;oCACzB;oCACAtG,WAAU;oCACV+F,UAAU,CAAC3D,SAASN,iBAAiBH,SAASoB,IAAI,IAAIzB;oCACtDyF,SAAS,IAAM,KAAKnC,kBAAkBjD,SAASoB,IAAI;oCACnDiE,MAAK;8CACN;;;2BAlCmDrF,SAASoB,IAAI;oBAwCzE;oBACC,CAACX,sBACA,KAACqD;wBAAIzF,WAAU;kCACZwB,EAAE;yBAEH;;;;;AAIZ,EAAC"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Button, toast, useConfig, useRouteTransition } from '@payloadcms/ui';
3
+ import { Button, toast, useConfig, useRouteTransition, useTranslation } from '@payloadcms/ui';
4
4
  import { useRouter } from 'next/navigation.js';
5
5
  import { formatAdminURL } from 'payload/shared';
6
6
  import { useState } from 'react';
@@ -9,6 +9,7 @@ export const TranslationActionsClient = ({ collectionSlug, docID, languages, sta
9
9
  const { config } = useConfig();
10
10
  const router = useRouter();
11
11
  const { startRouteTransition } = useRouteTransition();
12
+ const { t } = useTranslation();
12
13
  const [targetLanguage, setTargetLanguage] = useState('');
13
14
  const [targetID, setTargetID] = useState('');
14
15
  const [isBusy, setIsBusy] = useState(false);
@@ -18,7 +19,7 @@ export const TranslationActionsClient = ({ collectionSlug, docID, languages, sta
18
19
  });
19
20
  const createTranslation = async ()=>{
20
21
  if (!targetLanguage) {
21
- toast.error('Choose a target language.');
22
+ toast.error(t('payloadMultilang:chooseTargetLanguage'));
22
23
  return;
23
24
  }
24
25
  setIsBusy(true);
@@ -36,7 +37,7 @@ export const TranslationActionsClient = ({ collectionSlug, docID, languages, sta
36
37
  setIsBusy(false);
37
38
  if (!response.ok) {
38
39
  const result = await response.json().catch(()=>undefined);
39
- toast.error(result?.message || 'Translation could not be created.');
40
+ toast.error(result?.message || t('payloadMultilang:translationCouldNotBeCreated'));
40
41
  return;
41
42
  }
42
43
  const result = await response.json();
@@ -52,7 +53,7 @@ export const TranslationActionsClient = ({ collectionSlug, docID, languages, sta
52
53
  };
53
54
  const connectTranslation = async ()=>{
54
55
  if (!targetID || !targetLanguage) {
55
- toast.error('Target ID and language are required.');
56
+ toast.error(t('payloadMultilang:targetIDAndLanguageRequired'));
56
57
  return;
57
58
  }
58
59
  setIsBusy(true);
@@ -71,10 +72,10 @@ export const TranslationActionsClient = ({ collectionSlug, docID, languages, sta
71
72
  setIsBusy(false);
72
73
  if (!response.ok) {
73
74
  const result = await response.json().catch(()=>undefined);
74
- toast.error(result?.message || 'Translation could not be connected.');
75
+ toast.error(result?.message || t('payloadMultilang:translationCouldNotBeConnected'));
75
76
  return;
76
77
  }
77
- toast.success('Translation connected.');
78
+ toast.success(t('payloadMultilang:translationConnected'));
78
79
  startRouteTransition(()=>{
79
80
  router.refresh();
80
81
  });
@@ -93,10 +94,10 @@ export const TranslationActionsClient = ({ collectionSlug, docID, languages, sta
93
94
  });
94
95
  setIsBusy(false);
95
96
  if (!response.ok) {
96
- toast.error('Translation could not be disconnected.');
97
+ toast.error(t('payloadMultilang:translationCouldNotBeDisconnected'));
97
98
  return;
98
99
  }
99
- toast.success('Translation disconnected.');
100
+ toast.success(t('payloadMultilang:translationDisconnected'));
100
101
  startRouteTransition(()=>{
101
102
  router.refresh();
102
103
  });
@@ -106,7 +107,7 @@ export const TranslationActionsClient = ({ collectionSlug, docID, languages, sta
106
107
  className: "payload-multilang-panel",
107
108
  children: [
108
109
  /*#__PURE__*/ _jsx("h2", {
109
- children: "Translation actions"
110
+ children: t('payloadMultilang:translationActions')
110
111
  }),
111
112
  /*#__PURE__*/ _jsxs("div", {
112
113
  className: "payload-multilang-inline-form",
@@ -117,7 +118,7 @@ export const TranslationActionsClient = ({ collectionSlug, docID, languages, sta
117
118
  children: [
118
119
  /*#__PURE__*/ _jsx("option", {
119
120
  value: "",
120
- children: "Choose language"
121
+ children: t('payloadMultilang:chooseLanguage')
121
122
  }),
122
123
  availableLanguages.map((language)=>/*#__PURE__*/ _jsxs("option", {
123
124
  value: language.code,
@@ -132,7 +133,7 @@ export const TranslationActionsClient = ({ collectionSlug, docID, languages, sta
132
133
  disabled: isBusy || !targetLanguage,
133
134
  onClick: createTranslation,
134
135
  type: "button",
135
- children: "Create translation"
136
+ children: t('payloadMultilang:createTranslation')
136
137
  })
137
138
  ]
138
139
  }),
@@ -140,15 +141,16 @@ export const TranslationActionsClient = ({ collectionSlug, docID, languages, sta
140
141
  className: "payload-multilang-inline-form",
141
142
  children: [
142
143
  /*#__PURE__*/ _jsx("input", {
144
+ "aria-label": t('payloadMultilang:existingDocumentID'),
143
145
  onChange: (event)=>setTargetID(event.target.value),
144
- placeholder: "Existing document ID",
146
+ placeholder: t('payloadMultilang:existingDocumentID'),
145
147
  value: targetID
146
148
  }),
147
149
  /*#__PURE__*/ _jsx(Button, {
148
150
  disabled: isBusy || !targetID || !targetLanguage,
149
151
  onClick: connectTranslation,
150
152
  type: "button",
151
- children: "Connect existing"
153
+ children: t('payloadMultilang:connectExisting')
152
154
  })
153
155
  ]
154
156
  }),
@@ -157,7 +159,7 @@ export const TranslationActionsClient = ({ collectionSlug, docID, languages, sta
157
159
  disabled: isBusy,
158
160
  onClick: disconnectTranslation,
159
161
  type: "button",
160
- children: "Disconnect this document"
162
+ children: t('payloadMultilang:disconnectDocument')
161
163
  })
162
164
  ]
163
165
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/TranslationActionsClient.tsx"],"sourcesContent":["'use client'\n\nimport { Button, toast, useConfig, useRouteTransition } from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation.js'\nimport { formatAdminURL } from 'payload/shared'\nimport { useState } from 'react'\n\nimport '../styles/admin.css'\nimport type { MultilangLanguage, TranslationState } from '../types.js'\n\ntype Props = {\n collectionSlug: string\n docID: number | string\n languages: MultilangLanguage[]\n state: TranslationState\n}\n\nexport const TranslationActionsClient = ({\n collectionSlug,\n docID,\n languages,\n state,\n}: Props) => {\n const { config } = useConfig()\n const router = useRouter()\n const { startRouteTransition } = useRouteTransition()\n const [targetLanguage, setTargetLanguage] = useState('')\n const [targetID, setTargetID] = useState('')\n const [isBusy, setIsBusy] = useState(false)\n\n const collectionAPIPath = (path: string) =>\n formatAdminURL({\n apiRoute: config.routes.api,\n path: `/${collectionSlug}${path}`,\n })\n\n const createTranslation = async () => {\n if (!targetLanguage) {\n toast.error('Choose a target language.')\n return\n }\n\n setIsBusy(true)\n const response = await fetch(collectionAPIPath('/multilang/create'), {\n body: JSON.stringify({\n sourceId: docID,\n targetLanguage,\n }),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n setIsBusy(false)\n\n if (!response.ok) {\n const result = (await response.json().catch(() => undefined)) as\n | { message?: string }\n | undefined\n toast.error(result?.message || 'Translation could not be created.')\n return\n }\n\n const result = (await response.json()) as { doc?: { id?: number | string } }\n\n const documentID = result.doc?.id\n\n if (documentID) {\n startRouteTransition(() => {\n router.push(\n formatAdminURL({\n adminRoute: config.routes.admin,\n path: `/collections/${collectionSlug}/${documentID}`,\n }),\n )\n })\n }\n }\n\n const connectTranslation = async () => {\n if (!targetID || !targetLanguage) {\n toast.error('Target ID and language are required.')\n return\n }\n\n setIsBusy(true)\n const response = await fetch(collectionAPIPath('/multilang/connect'), {\n body: JSON.stringify({\n sourceId: docID,\n targetId: targetID,\n targetLanguage,\n }),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n setIsBusy(false)\n\n if (!response.ok) {\n const result = (await response.json().catch(() => undefined)) as\n | { message?: string }\n | undefined\n toast.error(result?.message || 'Translation could not be connected.')\n return\n }\n\n toast.success('Translation connected.')\n startRouteTransition(() => {\n router.refresh()\n })\n }\n\n const disconnectTranslation = async () => {\n setIsBusy(true)\n const response = await fetch(collectionAPIPath('/multilang/disconnect'), {\n body: JSON.stringify({ id: docID }),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n setIsBusy(false)\n\n if (!response.ok) {\n toast.error('Translation could not be disconnected.')\n return\n }\n\n toast.success('Translation disconnected.')\n startRouteTransition(() => {\n router.refresh()\n })\n }\n\n const availableLanguages = languages.filter(\n (language) => !state.translations[language.code],\n )\n\n return (\n <section className=\"payload-multilang-panel\">\n <h2>Translation actions</h2>\n <div className=\"payload-multilang-inline-form\">\n <select\n onChange={(event) => setTargetLanguage(event.target.value)}\n value={targetLanguage}\n >\n <option value=\"\">Choose language</option>\n {availableLanguages.map((language) => (\n <option key={language.code} value={language.code}>\n {language.flagLabel ? `${language.flagLabel} ` : ''}\n {language.name}\n </option>\n ))}\n </select>\n <Button disabled={isBusy || !targetLanguage} onClick={createTranslation} type=\"button\">\n Create translation\n </Button>\n </div>\n\n <div className=\"payload-multilang-inline-form\">\n <input\n onChange={(event) => setTargetID(event.target.value)}\n placeholder=\"Existing document ID\"\n value={targetID}\n />\n <Button disabled={isBusy || !targetID || !targetLanguage} onClick={connectTranslation} type=\"button\">\n Connect existing\n </Button>\n </div>\n\n <Button buttonStyle=\"secondary\" disabled={isBusy} onClick={disconnectTranslation} type=\"button\">\n Disconnect this document\n </Button>\n </section>\n )\n}\n"],"names":["Button","toast","useConfig","useRouteTransition","useRouter","formatAdminURL","useState","TranslationActionsClient","collectionSlug","docID","languages","state","config","router","startRouteTransition","targetLanguage","setTargetLanguage","targetID","setTargetID","isBusy","setIsBusy","collectionAPIPath","path","apiRoute","routes","api","createTranslation","error","response","fetch","body","JSON","stringify","sourceId","credentials","headers","method","ok","result","json","catch","undefined","message","documentID","doc","id","push","adminRoute","admin","connectTranslation","targetId","success","refresh","disconnectTranslation","availableLanguages","filter","language","translations","code","section","className","h2","div","select","onChange","event","target","value","option","map","flagLabel","name","disabled","onClick","type","input","placeholder","buttonStyle"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/TranslationActionsClient.tsx"],"sourcesContent":["'use client'\n\nimport { Button, toast, useConfig, useRouteTransition, useTranslation } from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation.js'\nimport { formatAdminURL } from 'payload/shared'\nimport { useState } from 'react'\n\nimport '../styles/admin.css'\nimport type {\n PayloadMultilangTranslationKey,\n PayloadMultilangTranslations,\n} from '../translations.js'\nimport type { MultilangLanguage, TranslationState } from '../types.js'\n\ntype Props = {\n collectionSlug: string\n docID: number | string\n languages: MultilangLanguage[]\n state: TranslationState\n}\n\nexport const TranslationActionsClient = ({\n collectionSlug,\n docID,\n languages,\n state,\n}: Props) => {\n const { config } = useConfig()\n const router = useRouter()\n const { startRouteTransition } = useRouteTransition()\n const { t } = useTranslation<\n PayloadMultilangTranslations,\n PayloadMultilangTranslationKey\n >()\n const [targetLanguage, setTargetLanguage] = useState('')\n const [targetID, setTargetID] = useState('')\n const [isBusy, setIsBusy] = useState(false)\n\n const collectionAPIPath = (path: string) =>\n formatAdminURL({\n apiRoute: config.routes.api,\n path: `/${collectionSlug}${path}`,\n })\n\n const createTranslation = async () => {\n if (!targetLanguage) {\n toast.error(t('payloadMultilang:chooseTargetLanguage'))\n return\n }\n\n setIsBusy(true)\n const response = await fetch(collectionAPIPath('/multilang/create'), {\n body: JSON.stringify({\n sourceId: docID,\n targetLanguage,\n }),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n setIsBusy(false)\n\n if (!response.ok) {\n const result = (await response.json().catch(() => undefined)) as\n | { message?: string }\n | undefined\n toast.error(result?.message || t('payloadMultilang:translationCouldNotBeCreated'))\n return\n }\n\n const result = (await response.json()) as { doc?: { id?: number | string } }\n\n const documentID = result.doc?.id\n\n if (documentID) {\n startRouteTransition(() => {\n router.push(\n formatAdminURL({\n adminRoute: config.routes.admin,\n path: `/collections/${collectionSlug}/${documentID}`,\n }),\n )\n })\n }\n }\n\n const connectTranslation = async () => {\n if (!targetID || !targetLanguage) {\n toast.error(t('payloadMultilang:targetIDAndLanguageRequired'))\n return\n }\n\n setIsBusy(true)\n const response = await fetch(collectionAPIPath('/multilang/connect'), {\n body: JSON.stringify({\n sourceId: docID,\n targetId: targetID,\n targetLanguage,\n }),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n setIsBusy(false)\n\n if (!response.ok) {\n const result = (await response.json().catch(() => undefined)) as\n | { message?: string }\n | undefined\n toast.error(result?.message || t('payloadMultilang:translationCouldNotBeConnected'))\n return\n }\n\n toast.success(t('payloadMultilang:translationConnected'))\n startRouteTransition(() => {\n router.refresh()\n })\n }\n\n const disconnectTranslation = async () => {\n setIsBusy(true)\n const response = await fetch(collectionAPIPath('/multilang/disconnect'), {\n body: JSON.stringify({ id: docID }),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n setIsBusy(false)\n\n if (!response.ok) {\n toast.error(t('payloadMultilang:translationCouldNotBeDisconnected'))\n return\n }\n\n toast.success(t('payloadMultilang:translationDisconnected'))\n startRouteTransition(() => {\n router.refresh()\n })\n }\n\n const availableLanguages = languages.filter(\n (language) => !state.translations[language.code],\n )\n\n return (\n <section className=\"payload-multilang-panel\">\n <h2>{t('payloadMultilang:translationActions')}</h2>\n <div className=\"payload-multilang-inline-form\">\n <select\n onChange={(event) => setTargetLanguage(event.target.value)}\n value={targetLanguage}\n >\n <option value=\"\">{t('payloadMultilang:chooseLanguage')}</option>\n {availableLanguages.map((language) => (\n <option key={language.code} value={language.code}>\n {language.flagLabel ? `${language.flagLabel} ` : ''}\n {language.name}\n </option>\n ))}\n </select>\n <Button disabled={isBusy || !targetLanguage} onClick={createTranslation} type=\"button\">\n {t('payloadMultilang:createTranslation')}\n </Button>\n </div>\n\n <div className=\"payload-multilang-inline-form\">\n <input\n aria-label={t('payloadMultilang:existingDocumentID')}\n onChange={(event) => setTargetID(event.target.value)}\n placeholder={t('payloadMultilang:existingDocumentID')}\n value={targetID}\n />\n <Button disabled={isBusy || !targetID || !targetLanguage} onClick={connectTranslation} type=\"button\">\n {t('payloadMultilang:connectExisting')}\n </Button>\n </div>\n\n <Button buttonStyle=\"secondary\" disabled={isBusy} onClick={disconnectTranslation} type=\"button\">\n {t('payloadMultilang:disconnectDocument')}\n </Button>\n </section>\n )\n}\n"],"names":["Button","toast","useConfig","useRouteTransition","useTranslation","useRouter","formatAdminURL","useState","TranslationActionsClient","collectionSlug","docID","languages","state","config","router","startRouteTransition","t","targetLanguage","setTargetLanguage","targetID","setTargetID","isBusy","setIsBusy","collectionAPIPath","path","apiRoute","routes","api","createTranslation","error","response","fetch","body","JSON","stringify","sourceId","credentials","headers","method","ok","result","json","catch","undefined","message","documentID","doc","id","push","adminRoute","admin","connectTranslation","targetId","success","refresh","disconnectTranslation","availableLanguages","filter","language","translations","code","section","className","h2","div","select","onChange","event","target","value","option","map","flagLabel","name","disabled","onClick","type","input","aria-label","placeholder","buttonStyle"],"mappings":"AAAA;;AAEA,SAASA,MAAM,EAAEC,KAAK,EAAEC,SAAS,EAAEC,kBAAkB,EAAEC,cAAc,QAAQ,iBAAgB;AAC7F,SAASC,SAAS,QAAQ,qBAAoB;AAC9C,SAASC,cAAc,QAAQ,iBAAgB;AAC/C,SAASC,QAAQ,QAAQ,QAAO;AAEhC,OAAO,sBAAqB;AAc5B,OAAO,MAAMC,2BAA2B,CAAC,EACvCC,cAAc,EACdC,KAAK,EACLC,SAAS,EACTC,KAAK,EACC;IACN,MAAM,EAAEC,MAAM,EAAE,GAAGX;IACnB,MAAMY,SAAST;IACf,MAAM,EAAEU,oBAAoB,EAAE,GAAGZ;IACjC,MAAM,EAAEa,CAAC,EAAE,GAAGZ;IAId,MAAM,CAACa,gBAAgBC,kBAAkB,GAAGX,SAAS;IACrD,MAAM,CAACY,UAAUC,YAAY,GAAGb,SAAS;IACzC,MAAM,CAACc,QAAQC,UAAU,GAAGf,SAAS;IAErC,MAAMgB,oBAAoB,CAACC,OACzBlB,eAAe;YACbmB,UAAUZ,OAAOa,MAAM,CAACC,GAAG;YAC3BH,MAAM,CAAC,CAAC,EAAEf,iBAAiBe,MAAM;QACnC;IAEF,MAAMI,oBAAoB;QACxB,IAAI,CAACX,gBAAgB;YACnBhB,MAAM4B,KAAK,CAACb,EAAE;YACd;QACF;QAEAM,UAAU;QACV,MAAMQ,WAAW,MAAMC,MAAMR,kBAAkB,sBAAsB;YACnES,MAAMC,KAAKC,SAAS,CAAC;gBACnBC,UAAUzB;gBACVO;YACF;YACAmB,aAAa;YACbC,SAAS;gBACP,gBAAgB;YAClB;YACAC,QAAQ;QACV;QACAhB,UAAU;QAEV,IAAI,CAACQ,SAASS,EAAE,EAAE;YAChB,MAAMC,SAAU,MAAMV,SAASW,IAAI,GAAGC,KAAK,CAAC,IAAMC;YAGlD1C,MAAM4B,KAAK,CAACW,QAAQI,WAAW5B,EAAE;YACjC;QACF;QAEA,MAAMwB,SAAU,MAAMV,SAASW,IAAI;QAEnC,MAAMI,aAAaL,OAAOM,GAAG,EAAEC;QAE/B,IAAIF,YAAY;YACd9B,qBAAqB;gBACnBD,OAAOkC,IAAI,CACT1C,eAAe;oBACb2C,YAAYpC,OAAOa,MAAM,CAACwB,KAAK;oBAC/B1B,MAAM,CAAC,aAAa,EAAEf,eAAe,CAAC,EAAEoC,YAAY;gBACtD;YAEJ;QACF;IACF;IAEA,MAAMM,qBAAqB;QACzB,IAAI,CAAChC,YAAY,CAACF,gBAAgB;YAChChB,MAAM4B,KAAK,CAACb,EAAE;YACd;QACF;QAEAM,UAAU;QACV,MAAMQ,WAAW,MAAMC,MAAMR,kBAAkB,uBAAuB;YACpES,MAAMC,KAAKC,SAAS,CAAC;gBACnBC,UAAUzB;gBACV0C,UAAUjC;gBACVF;YACF;YACAmB,aAAa;YACbC,SAAS;gBACP,gBAAgB;YAClB;YACAC,QAAQ;QACV;QACAhB,UAAU;QAEV,IAAI,CAACQ,SAASS,EAAE,EAAE;YAChB,MAAMC,SAAU,MAAMV,SAASW,IAAI,GAAGC,KAAK,CAAC,IAAMC;YAGlD1C,MAAM4B,KAAK,CAACW,QAAQI,WAAW5B,EAAE;YACjC;QACF;QAEAf,MAAMoD,OAAO,CAACrC,EAAE;QAChBD,qBAAqB;YACnBD,OAAOwC,OAAO;QAChB;IACF;IAEA,MAAMC,wBAAwB;QAC5BjC,UAAU;QACV,MAAMQ,WAAW,MAAMC,MAAMR,kBAAkB,0BAA0B;YACvES,MAAMC,KAAKC,SAAS,CAAC;gBAAEa,IAAIrC;YAAM;YACjC0B,aAAa;YACbC,SAAS;gBACP,gBAAgB;YAClB;YACAC,QAAQ;QACV;QACAhB,UAAU;QAEV,IAAI,CAACQ,SAASS,EAAE,EAAE;YAChBtC,MAAM4B,KAAK,CAACb,EAAE;YACd;QACF;QAEAf,MAAMoD,OAAO,CAACrC,EAAE;QAChBD,qBAAqB;YACnBD,OAAOwC,OAAO;QAChB;IACF;IAEA,MAAME,qBAAqB7C,UAAU8C,MAAM,CACzC,CAACC,WAAa,CAAC9C,MAAM+C,YAAY,CAACD,SAASE,IAAI,CAAC;IAGlD,qBACE,MAACC;QAAQC,WAAU;;0BACjB,KAACC;0BAAI/C,EAAE;;0BACP,MAACgD;gBAAIF,WAAU;;kCACb,MAACG;wBACCC,UAAU,CAACC,QAAUjD,kBAAkBiD,MAAMC,MAAM,CAACC,KAAK;wBACzDA,OAAOpD;;0CAEP,KAACqD;gCAAOD,OAAM;0CAAIrD,EAAE;;4BACnBwC,mBAAmBe,GAAG,CAAC,CAACb,yBACvB,MAACY;oCAA2BD,OAAOX,SAASE,IAAI;;wCAC7CF,SAASc,SAAS,GAAG,GAAGd,SAASc,SAAS,CAAC,CAAC,CAAC,GAAG;wCAChDd,SAASe,IAAI;;mCAFHf,SAASE,IAAI;;;kCAM9B,KAAC5D;wBAAO0E,UAAUrD,UAAU,CAACJ;wBAAgB0D,SAAS/C;wBAAmBgD,MAAK;kCAC3E5D,EAAE;;;;0BAIP,MAACgD;gBAAIF,WAAU;;kCACb,KAACe;wBACCC,cAAY9D,EAAE;wBACdkD,UAAU,CAACC,QAAU/C,YAAY+C,MAAMC,MAAM,CAACC,KAAK;wBACnDU,aAAa/D,EAAE;wBACfqD,OAAOlD;;kCAET,KAACnB;wBAAO0E,UAAUrD,UAAU,CAACF,YAAY,CAACF;wBAAgB0D,SAASxB;wBAAoByB,MAAK;kCACzF5D,EAAE;;;;0BAIP,KAAChB;gBAAOgF,aAAY;gBAAYN,UAAUrD;gBAAQsD,SAASpB;gBAAuBqB,MAAK;0BACpF5D,EAAE;;;;AAIX,EAAC"}
@@ -3,6 +3,7 @@ import { DEFAULT_FIELD_NAMES } from '../constants.js';
3
3
  import { asDocument, getID, getStringValue } from '../lib/data.js';
4
4
  import { getPayloadMultilangCustom } from './config.js';
5
5
  import { TranslationColumnCellClient } from './TranslationColumnCellClient.js';
6
+ const translate = (props, key, options)=>props.i18n?.t ? props.i18n.t(key, options) : key;
6
7
  const getCollectionConfig = (props)=>props.collectionConfig || props.payload.collections[props.collectionSlug]?.config;
7
8
  const getFieldNames = (props)=>({
8
9
  ...DEFAULT_FIELD_NAMES,
@@ -53,7 +54,9 @@ export const TranslationColumnCell = async (props)=>{
53
54
  }
54
55
  return /*#__PURE__*/ _jsx("div", {
55
56
  className: "payload-multilang-column-stack",
56
- title: currentLanguage ? undefined : storedLanguage ? `Unassigned; stored language "${storedLanguage}" is not configured` : 'Unassigned',
57
+ title: currentLanguage ? undefined : storedLanguage ? translate(props, 'payloadMultilang:unassignedStoredLanguageNotConfigured', {
58
+ language: storedLanguage
59
+ }) : translate(props, 'payloadMultilang:unassigned'),
57
60
  children: languages.map((language)=>/*#__PURE__*/ _jsx(TranslationColumnCellClient, {
58
61
  collectionSlug: collectionConfig.slug,
59
62
  current: currentLanguage === language.code,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/TranslationColumnCell.tsx"],"sourcesContent":["import type { CollectionSlug, DefaultServerCellComponentProps } from 'payload'\n\nimport { DEFAULT_FIELD_NAMES } from '../constants.js'\nimport { asDocument, getID, getStringValue } from '../lib/data.js'\nimport type { MultilangFieldNames, MultilangLanguage } from '../types.js'\nimport { getPayloadMultilangCustom } from './config.js'\nimport { TranslationColumnCellClient } from './TranslationColumnCellClient.js'\n\nconst getCollectionConfig = (props: DefaultServerCellComponentProps) =>\n props.collectionConfig || props.payload.collections[props.collectionSlug]?.config\n\nconst getFieldNames = (\n props: DefaultServerCellComponentProps,\n): MultilangFieldNames => ({\n ...DEFAULT_FIELD_NAMES,\n ...(getPayloadMultilangCustom(getCollectionConfig(props)?.admin?.custom)\n .fieldNames || {}),\n})\n\nconst getLanguages = (\n props: DefaultServerCellComponentProps,\n): MultilangLanguage[] => {\n const languages = getPayloadMultilangCustom(\n getCollectionConfig(props)?.admin?.custom,\n ).languages\n\n return Array.isArray(languages) ? languages : []\n}\n\nexport const TranslationColumnCell = async (\n props: DefaultServerCellComponentProps,\n) => {\n const fieldNames = getFieldNames(props)\n const languages = getLanguages(props)\n const collectionConfig = getCollectionConfig(props)\n const rowData = asDocument(props.rowData)\n const sourceID = getID(rowData.id)\n const configuredLanguageCodes = new Set(languages.map((language) => language.code))\n\n if (!collectionConfig || !languages.length || !sourceID) {\n return (\n <span className=\"payload-multilang-cell payload-multilang-cell--muted\">\n -\n </span>\n )\n }\n\n const storedLanguage = getStringValue(rowData[fieldNames.language])\n const currentLanguage =\n storedLanguage && configuredLanguageCodes.has(storedLanguage)\n ? storedLanguage\n : undefined\n const group = getStringValue(rowData[fieldNames.group])\n let translationsByLanguage: Record<string, number | string> = {}\n\n if (group) {\n const { docs } = await props.payload.find({\n collection: collectionConfig.slug as CollectionSlug,\n depth: 0,\n limit: 200,\n overrideAccess: true,\n where: {\n [fieldNames.group]: {\n equals: group,\n },\n },\n })\n\n translationsByLanguage = docs.reduce<Record<string, number | string>>(\n (acc, doc) => {\n const data = asDocument(doc)\n const language = getStringValue(data[fieldNames.language])\n const id = getID(data.id)\n\n if (language && id) {\n acc[language] = id\n }\n\n return acc\n },\n {},\n )\n }\n\n return (\n <div\n className=\"payload-multilang-column-stack\"\n title={\n currentLanguage\n ? undefined\n : storedLanguage\n ? `Unassigned; stored language \"${storedLanguage}\" is not configured`\n : 'Unassigned'\n }\n >\n {languages.map((language) => (\n <TranslationColumnCellClient\n collectionSlug={collectionConfig.slug}\n current={currentLanguage === language.code}\n flagLabel={language.flagLabel}\n key={language.code}\n sourceID={sourceID}\n targetLanguage={language.code}\n targetLanguageName={language.name}\n translationID={translationsByLanguage[language.code]}\n />\n ))}\n </div>\n )\n}\n"],"names":["DEFAULT_FIELD_NAMES","asDocument","getID","getStringValue","getPayloadMultilangCustom","TranslationColumnCellClient","getCollectionConfig","props","collectionConfig","payload","collections","collectionSlug","config","getFieldNames","admin","custom","fieldNames","getLanguages","languages","Array","isArray","TranslationColumnCell","rowData","sourceID","id","configuredLanguageCodes","Set","map","language","code","length","span","className","storedLanguage","currentLanguage","has","undefined","group","translationsByLanguage","docs","find","collection","slug","depth","limit","overrideAccess","where","equals","reduce","acc","doc","data","div","title","current","flagLabel","targetLanguage","targetLanguageName","name","translationID"],"mappings":";AAEA,SAASA,mBAAmB,QAAQ,kBAAiB;AACrD,SAASC,UAAU,EAAEC,KAAK,EAAEC,cAAc,QAAQ,iBAAgB;AAElE,SAASC,yBAAyB,QAAQ,cAAa;AACvD,SAASC,2BAA2B,QAAQ,mCAAkC;AAE9E,MAAMC,sBAAsB,CAACC,QAC3BA,MAAMC,gBAAgB,IAAID,MAAME,OAAO,CAACC,WAAW,CAACH,MAAMI,cAAc,CAAC,EAAEC;AAE7E,MAAMC,gBAAgB,CACpBN,QACyB,CAAA;QACzB,GAAGP,mBAAmB;QACtB,GAAII,0BAA0BE,oBAAoBC,QAAQO,OAAOC,QAC9DC,UAAU,IAAI,CAAC,CAAC;IACrB,CAAA;AAEA,MAAMC,eAAe,CACnBV;IAEA,MAAMW,YAAYd,0BAChBE,oBAAoBC,QAAQO,OAAOC,QACnCG,SAAS;IAEX,OAAOC,MAAMC,OAAO,CAACF,aAAaA,YAAY,EAAE;AAClD;AAEA,OAAO,MAAMG,wBAAwB,OACnCd;IAEA,MAAMS,aAAaH,cAAcN;IACjC,MAAMW,YAAYD,aAAaV;IAC/B,MAAMC,mBAAmBF,oBAAoBC;IAC7C,MAAMe,UAAUrB,WAAWM,MAAMe,OAAO;IACxC,MAAMC,WAAWrB,MAAMoB,QAAQE,EAAE;IACjC,MAAMC,0BAA0B,IAAIC,IAAIR,UAAUS,GAAG,CAAC,CAACC,WAAaA,SAASC,IAAI;IAEjF,IAAI,CAACrB,oBAAoB,CAACU,UAAUY,MAAM,IAAI,CAACP,UAAU;QACvD,qBACE,KAACQ;YAAKC,WAAU;sBAAuD;;IAI3E;IAEA,MAAMC,iBAAiB9B,eAAemB,OAAO,CAACN,WAAWY,QAAQ,CAAC;IAClE,MAAMM,kBACJD,kBAAkBR,wBAAwBU,GAAG,CAACF,kBAC1CA,iBACAG;IACN,MAAMC,QAAQlC,eAAemB,OAAO,CAACN,WAAWqB,KAAK,CAAC;IACtD,IAAIC,yBAA0D,CAAC;IAE/D,IAAID,OAAO;QACT,MAAM,EAAEE,IAAI,EAAE,GAAG,MAAMhC,MAAME,OAAO,CAAC+B,IAAI,CAAC;YACxCC,YAAYjC,iBAAiBkC,IAAI;YACjCC,OAAO;YACPC,OAAO;YACPC,gBAAgB;YAChBC,OAAO;gBACL,CAAC9B,WAAWqB,KAAK,CAAC,EAAE;oBAClBU,QAAQV;gBACV;YACF;QACF;QAEAC,yBAAyBC,KAAKS,MAAM,CAClC,CAACC,KAAKC;YACJ,MAAMC,OAAOlD,WAAWiD;YACxB,MAAMtB,WAAWzB,eAAegD,IAAI,CAACnC,WAAWY,QAAQ,CAAC;YACzD,MAAMJ,KAAKtB,MAAMiD,KAAK3B,EAAE;YAExB,IAAII,YAAYJ,IAAI;gBAClByB,GAAG,CAACrB,SAAS,GAAGJ;YAClB;YAEA,OAAOyB;QACT,GACA,CAAC;IAEL;IAEA,qBACE,KAACG;QACCpB,WAAU;QACVqB,OACEnB,kBACIE,YACAH,iBACE,CAAC,6BAA6B,EAAEA,eAAe,mBAAmB,CAAC,GACnE;kBAGPf,UAAUS,GAAG,CAAC,CAACC,yBACd,KAACvB;gBACCM,gBAAgBH,iBAAiBkC,IAAI;gBACrCY,SAASpB,oBAAoBN,SAASC,IAAI;gBAC1C0B,WAAW3B,SAAS2B,SAAS;gBAE7BhC,UAAUA;gBACViC,gBAAgB5B,SAASC,IAAI;gBAC7B4B,oBAAoB7B,SAAS8B,IAAI;gBACjCC,eAAerB,sBAAsB,CAACV,SAASC,IAAI,CAAC;eAJ/CD,SAASC,IAAI;;AAS5B,EAAC"}
1
+ {"version":3,"sources":["../../src/components/TranslationColumnCell.tsx"],"sourcesContent":["import type { DefaultServerCellComponentProps } from 'payload'\n\nimport type { PayloadMultilangTranslationKey } from '../translations.js'\nimport type { MultilangFieldNames, MultilangLanguage } from '../types.js'\n\nimport { DEFAULT_FIELD_NAMES } from '../constants.js'\nimport { asDocument, getID, getStringValue } from '../lib/data.js'\nimport { getPayloadMultilangCustom } from './config.js'\nimport { TranslationColumnCellClient } from './TranslationColumnCellClient.js'\n\nconst translate = (\n props: DefaultServerCellComponentProps,\n key: PayloadMultilangTranslationKey,\n options?: Record<string, unknown>,\n): string => props.i18n?.t ? props.i18n.t(key as never, options) : key\n\nconst getCollectionConfig = (props: DefaultServerCellComponentProps) =>\n props.collectionConfig || props.payload.collections[props.collectionSlug]?.config\n\nconst getFieldNames = (\n props: DefaultServerCellComponentProps,\n): MultilangFieldNames => ({\n ...DEFAULT_FIELD_NAMES,\n ...(getPayloadMultilangCustom(getCollectionConfig(props)?.admin?.custom)\n .fieldNames || {}),\n})\n\nconst getLanguages = (\n props: DefaultServerCellComponentProps,\n): MultilangLanguage[] => {\n const languages = getPayloadMultilangCustom(\n getCollectionConfig(props)?.admin?.custom,\n ).languages\n\n return Array.isArray(languages) ? languages : []\n}\n\nexport const TranslationColumnCell = async (\n props: DefaultServerCellComponentProps,\n) => {\n const fieldNames = getFieldNames(props)\n const languages = getLanguages(props)\n const collectionConfig = getCollectionConfig(props)\n const rowData = asDocument(props.rowData)\n const sourceID = getID(rowData.id)\n const configuredLanguageCodes = new Set(languages.map((language) => language.code))\n\n if (!collectionConfig || !languages.length || !sourceID) {\n return (\n <span className=\"payload-multilang-cell payload-multilang-cell--muted\">\n -\n </span>\n )\n }\n\n const storedLanguage = getStringValue(rowData[fieldNames.language])\n const currentLanguage =\n storedLanguage && configuredLanguageCodes.has(storedLanguage)\n ? storedLanguage\n : undefined\n const group = getStringValue(rowData[fieldNames.group])\n let translationsByLanguage: Record<string, number | string> = {}\n\n if (group) {\n const { docs } = await props.payload.find({\n collection: collectionConfig.slug,\n depth: 0,\n limit: 200,\n overrideAccess: true,\n where: {\n [fieldNames.group]: {\n equals: group,\n },\n },\n })\n\n translationsByLanguage = docs.reduce<Record<string, number | string>>(\n (acc, doc) => {\n const data = asDocument(doc)\n const language = getStringValue(data[fieldNames.language])\n const id = getID(data.id)\n\n if (language && id) {\n acc[language] = id\n }\n\n return acc\n },\n {},\n )\n }\n\n return (\n <div\n className=\"payload-multilang-column-stack\"\n title={\n currentLanguage\n ? undefined\n : storedLanguage\n ? translate(\n props,\n 'payloadMultilang:unassignedStoredLanguageNotConfigured',\n { language: storedLanguage },\n )\n : translate(props, 'payloadMultilang:unassigned')\n }\n >\n {languages.map((language) => (\n <TranslationColumnCellClient\n collectionSlug={collectionConfig.slug}\n current={currentLanguage === language.code}\n flagLabel={language.flagLabel}\n key={language.code}\n sourceID={sourceID}\n targetLanguage={language.code}\n targetLanguageName={language.name}\n translationID={translationsByLanguage[language.code]}\n />\n ))}\n </div>\n )\n}\n"],"names":["DEFAULT_FIELD_NAMES","asDocument","getID","getStringValue","getPayloadMultilangCustom","TranslationColumnCellClient","translate","props","key","options","i18n","t","getCollectionConfig","collectionConfig","payload","collections","collectionSlug","config","getFieldNames","admin","custom","fieldNames","getLanguages","languages","Array","isArray","TranslationColumnCell","rowData","sourceID","id","configuredLanguageCodes","Set","map","language","code","length","span","className","storedLanguage","currentLanguage","has","undefined","group","translationsByLanguage","docs","find","collection","slug","depth","limit","overrideAccess","where","equals","reduce","acc","doc","data","div","title","current","flagLabel","targetLanguage","targetLanguageName","name","translationID"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { toast, useConfig, useRouteTransition } from '@payloadcms/ui';
3
+ import { toast, useConfig, useRouteTransition, useTranslation } from '@payloadcms/ui';
4
4
  import { useRouter } from 'next/navigation.js';
5
5
  import { formatAdminURL } from 'payload/shared';
6
6
  import { useState } from 'react';
@@ -32,6 +32,7 @@ export const TranslationColumnCellClient = ({ collectionSlug, current, flagLabel
32
32
  const { config } = useConfig();
33
33
  const router = useRouter();
34
34
  const { isTransitioning, startRouteTransition } = useRouteTransition();
35
+ const { t } = useTranslation();
35
36
  const [isBusy, setIsBusy] = useState(false);
36
37
  const documentURL = (documentID)=>formatAdminURL({
37
38
  adminRoute: config.routes.admin,
@@ -44,7 +45,7 @@ export const TranslationColumnCellClient = ({ collectionSlug, current, flagLabel
44
45
  };
45
46
  const createTranslation = async ()=>{
46
47
  if (!sourceID) {
47
- toast.error('Save the document before creating translations.');
48
+ toast.error(t('payloadMultilang:saveBeforeCreatingTranslations'));
48
49
  return;
49
50
  }
50
51
  setIsBusy(true);
@@ -65,7 +66,7 @@ export const TranslationColumnCellClient = ({ collectionSlug, current, flagLabel
65
66
  setIsBusy(false);
66
67
  if (!response.ok) {
67
68
  const result = await response.json().catch(()=>undefined);
68
- toast.error(result?.message || 'Translation could not be created.');
69
+ toast.error(result?.message || t('payloadMultilang:translationCouldNotBeCreated'));
69
70
  return;
70
71
  }
71
72
  const result = await response.json();
@@ -82,23 +83,31 @@ export const TranslationColumnCellClient = ({ collectionSlug, current, flagLabel
82
83
  }
83
84
  if (translationID) {
84
85
  return /*#__PURE__*/ _jsx("a", {
86
+ "aria-label": t('payloadMultilang:editTranslationFor', {
87
+ language: targetLanguageName
88
+ }),
85
89
  className: "payload-multilang-cell-action",
86
90
  href: documentURL(translationID),
87
91
  onClick: (event)=>{
88
92
  event.preventDefault();
89
93
  navigateToTranslation(translationID);
90
94
  },
91
- "aria-label": `Edit ${targetLanguageName} translation`,
92
- title: `Edit ${targetLanguageName} translation`,
95
+ title: t('payloadMultilang:editTranslationFor', {
96
+ language: targetLanguageName
97
+ }),
93
98
  children: /*#__PURE__*/ _jsx(PenIcon, {})
94
99
  });
95
100
  }
96
101
  return /*#__PURE__*/ _jsx("button", {
97
- "aria-label": `Create ${targetLanguageName} translation`,
102
+ "aria-label": t('payloadMultilang:createTranslationFor', {
103
+ language: targetLanguageName
104
+ }),
98
105
  className: "payload-multilang-icon-button",
99
106
  disabled: !sourceID || isBusy || isTransitioning,
100
107
  onClick: ()=>void createTranslation(),
101
- title: `Create ${targetLanguageName} translation`,
108
+ title: t('payloadMultilang:createTranslationFor', {
109
+ language: targetLanguageName
110
+ }),
102
111
  type: "button",
103
112
  children: "+"
104
113
  });