@sanity/document-internationalization 2.0.0-studio-v3-plugin-v2.2 → 2.0.0-studio-v3-plugin-v2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # @sanity/document-internationalization
1
+ # @sanity/document-internationalization
2
2
 
3
- - This is a completely new, **Sanity Studio v3 exclusive version** of @sanity/document-internationalization released as v2.0.0 which contains new features and requires content migrations to upgrade from previous versions. There is example code below.
3
+ - This is a completely new, **Sanity Studio v3 exclusive version** of @sanity/document-internationalization released as v2.0.0 which contains new features and requires content migrations to upgrade from previous versions. There is an example code below.
4
4
 
5
5
  - For the **Studio v3 compatible version** of the original plugin, please install v1.0.0 and above.
6
6
 
@@ -43,7 +43,6 @@ yarn add @sanity/document-internationalization@studio-v3-plugin-v2
43
43
  Add it as a plugin in sanity.config.ts (or .js):
44
44
 
45
45
  ```ts
46
-
47
46
  // sanity.config.ts
48
47
  import {createConfig} from 'sanity'
49
48
  import {documentInternationalization} from '@sanity/document-internationalization'
@@ -52,16 +51,20 @@ export const createConfig({
52
51
  // ...
53
52
  plugins: [
54
53
  documentInternationalization({
55
- // Required
54
+ // Required, either:
55
+ // An array of supported languages
56
56
  supportedLanguages: [
57
57
  {id: 'nb', title: 'Norwegian (Bokmål)'},
58
58
  {id: 'nn', title: 'Norwegian (Nynorsk)'},
59
59
  {id: 'en', title: 'English'}
60
60
  ],
61
+ // OR a function that takes the client and returns a promise of an array of supported languages
62
+ supportedLanguages: (client) => client.fetch(`*[_type == "language"]{id, title}`),
63
+ // Required
61
64
  schemaTypes: ['lesson'],
62
65
  // Optional
63
66
  languageField: `language` // defauts to "language"
64
- // Requires access to the Publishing API
67
+ // Optional, requires access to the Publishing API
65
68
  bulkPublish: true // defaults to false
66
69
  })
67
70
  ]
@@ -147,7 +150,8 @@ There are two scripts in the `./migrations` folder of this repository. They cont
147
150
 
148
151
  ## Roadmap
149
152
 
150
- - [ ] Asynchronous language plugin config option
153
+ - [ ] Stabilize bulk publishing feature
154
+ - [x] Asynchronous language plugin config option
151
155
  - [ ] Export a validator to allow the same slug on connected translations
152
156
  - [ ] Guidance to copy/paste changes between documents
153
157
  - [ ] Guidance on handling singletons
@@ -172,10 +176,10 @@ on how to run this plugin with hotreload in the studio.
172
176
 
173
177
  ### Release new version
174
178
 
175
- Run ["CI & Release" workflow](https://github.com/sanity-io/document-internationalization/actions/workflows/main.yml).
179
+ Run the ["CI & Release" workflow](https://github.com/sanity-io/document-internationalization/actions/workflows/main.yml).
176
180
  Make sure to select the main branch and check "Release new version".
177
181
 
178
- Semantic release will only release on configured branches, so it is safe to run release on any branch.
182
+ The semantic release will only release on configured branches, so it is safe to run the release on any branch.
179
183
 
180
184
  ## License
181
185
 
package/lib/index.esm.js CHANGED
@@ -1,2 +1 @@
1
- function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function t(t){for(var a=1;a<arguments.length;a++){var r=null!=arguments[a]?arguments[a]:{};a%2?e(Object(r),!0).forEach((function(e){n(t,e,r[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):e(Object(r)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(r,e))}))}return t}function n(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}import{jsx as a,jsxs as r,Fragment as i}from"react/jsx-runtime";import{defineType as l,defineField as o,useClient as s,useEditState as c,useValidationStatus as d,useSchema as u,SanityPreview as p,useWorkspace as m,definePlugin as h}from"sanity";import{internationalizedArray as g}from"sanity-plugin-internationalized-array";import{useToast as f,Button as y,Flex as v,Spinner as b,Text as _,Box as T,Badge as k,useClickOutside as I,Card as O,Stack as j,Popover as P}from"@sanity/ui";import{TranslateIcon as S,SplitVerticalIcon as w,CheckmarkIcon as x,AddIcon as C,CogIcon as D,ChevronRightIcon as F}from"@sanity/icons";import z,{useCallback as E,useState as L}from"react";import{uuid as B}from"@sanity/uuid";import{usePaneRouter as M}from"sanity/desk";import{RouterContext as $}from"sanity/router";import{useListeningQuery as U}from"sanity-plugin-utils";var A=e=>l({type:"document",name:"translation.metadata",title:"Translation metadata",icon:S,liveEdit:!0,fields:[o({name:"translations",type:"internationalizedArrayReference"}),o({name:"schemaTypes",description:"Used to filter the reference fields above so all translations share the same types.",type:"array",of:[{type:"string"}],options:{list:e},readOnly:e=>{let{value:t}=e;return Boolean(t)}})],preview:{select:{translations:"translations",documentSchemaTypes:"schemaTypes"},prepare(e){const{translations:t,documentSchemaTypes:n}=e,a=1===t.length?"1 Translation":"".concat(t.length," Translations"),r=t.length?t.map((e=>e._key.toUpperCase())).join(", "):"";return{title:a,subtitle:[r?"(".concat(r,")"):null,(null==n?void 0:n.length)?n.map((e=>e.toUpperCase())).join(", "):"No Schemas Defined"].filter(Boolean).join(" ")}}}});function N(e,t){const n=z.useContext($),{routerPanesState:a,groupIndex:r}=M();return z.useCallback((()=>{if(!n||!e||!t)return;const i=[...a];i.splice(r+1,0,[{id:e,params:{type:t}}]);const l=n.resolvePathFromState({panes:i});n.navigateUrl({path:l})}),[e,t,n,a,r])}function q(e,t,n){return{_key:e,value:{_type:"reference",_ref:t,_weak:!0,_strengthenOnPublish:{type:n}}}}function R(e){var n;const{index:i,language:l,languageField:o,schemaType:c,documentId:d,disabled:u,current:p,sourceId:m,sourceLanguageId:h,metadata:g,translation:I}=e,O=s(),j=f(),P=N(null==(n=null==I?void 0:I.value)?void 0:n._ref,c),S=E((()=>P()),[P]),D=E((async()=>{var e;const n=Boolean(null==g?void 0:g._id),a=O.transaction(),r=d.startsWith("drafts.")?[d,d.replace("drafts.","")]:[d,"drafts.".concat(d)],s=t(t({},await O.fetch("*[_id in $ids]|order(_updatedAt desc)[0]",{ids:r})),{},{_id:"drafts.".concat(B()),[o]:l.id});a.create(s);const u=null!=(e=null==g?void 0:g._id)?e:B(),p=q(l.id,s._id.replace("drafts.",""),c);if(n){const e="translations[".concat(i-1,"]"),t=O.patch(u).setIfMissing({translations:[]}).insert("before",e,[p]);a.patch(t)}else{const e=h?q(h,m,c):null;a.createIfNotExists({_id:u,_type:"translation.metadata",schemaTypes:[c],translations:[p,e].filter(Boolean)})}a.commit().then((()=>j.push({status:"success",title:"Created ".concat(l.title," translation"),description:n?"Updated Translations Metadata":"Created Translations Metadata"}))).catch((e=>(console.error(e),j.push({status:"error",title:"Error creating translation",description:e.message}))))}),[O,d,i,l,o,null==g?void 0:g._id,c,m,h,j]);return a(y,{onClick:I?S:D,mode:p?"default":"bleed",disabled:u||p,children:r(v,{gap:3,align:"center",children:[u?a(b,{}):a(_,{size:2,children:a(I?w:p?x:C,{})}),a(T,{flex:1,children:a(_,{children:l.title})}),a(k,{tone:u||p?"default":"primary",children:l.id})]})})}function V(e){const{id:t}=e,n=N(t,"translation.metadata");return a(y,{disabled:!t,mode:"ghost",text:"Manage Translations",icon:D,onClick:()=>n()})}function W(e){const{language:t,languageField:n,documentId:r,schemaType:i,source:l,disabled:o=!1}=e,c=s(),d=f(),u=z.useCallback((()=>{const e=l?l._id:"draft.".concat(r),a=c.transaction();l||a.createIfNotExists({_id:e,_type:i});const o=c.patch(e).set({[n]:t.id});a.patch(o),a.commit().then((()=>{d.push({title:"Set document language to ".concat(t.title),status:"success"})})).catch((e=>(console.error(e),d.push({title:"Failed to set document language to ".concat(t.title),status:"error"}))))}),[l,r,c,n,t,i,d]);return a(y,{mode:"ghost",text:t.title,icon:F,onClick:()=>u(),disabled:o,justify:"flex-start"})}function G(e){const{supportedLanguages:t,schemaType:n,documentId:l,languageField:o}=e,[s,d]=L(!1),u=E((()=>d((e=>!e))),[]),[p,m]=L(null),[h,g]=L(null),f=E((()=>d(!1)),[]);I(f,[p,h]);const{data:v,loading:b,error:k}=function(e,t){const{data:n,loading:a,error:r}=U("*[_type == $translationSchema && $id in translations[].value._ref][0]",{params:{id:e,translationSchema:"translation.metadata"}});return{data:n,loading:a,error:r}}(l),{draft:w,published:x}=c(l,n),C=w||x,D=null==C?void 0:C[o],F=t.some((e=>e.id===D)),z=a(T,{overflow:"auto",children:k?a(O,{tone:"critical",padding:2,children:r(_,{children:["Error: ",k]})}):r(j,{padding:1,space:1,children:[t.length>0?r(i,{children:[t.map(((e,t)=>{var r;return!b&&D&&F?a(R,{index:t,language:e,languageField:o,schemaType:n,documentId:l,disabled:b,current:e.id===D,metadata:v,sourceId:l,sourceLanguageId:D,translation:null==v?void 0:v.translations.find((t=>t._key===e.id))},e.id):a(W,{languageField:o,source:C,documentId:l,schemaType:n,language:e,disabled:null!=(r=null==v?void 0:v.translations.filter((e=>{var t;return(null==(t=null==e?void 0:e.value)?void 0:t._ref)!==l})).some((t=>t._key===e.id)))&&r},e.id)})),b?null:r(i,{children:[D?null:a(O,{tone:"caution",padding:3,children:r(_,{size:1,children:["Choose a language to ",a("br",{}),"apply to ",a("strong",{children:"this Document"})]})}),D&&!F?a(O,{tone:"caution",padding:3,children:r(_,{size:1,children:["Change the current language value ",a("code",{children:D}),a("br",{}),"to one of the supported languages"]})}):null]})]}):null,a(V,{id:null==v?void 0:v._id})]})});return a(P,{constrainSize:!0,content:z,open:s,portal:!0,ref:g,children:a(y,{text:"Translations",mode:"bleed",disabled:!C,tone:!C||!b&&D&&F?void 0:"caution",icon:S,onClick:u,ref:m,selected:s})})}function H(e){const{id:t,addId:n,removeId:r}=e,i=c(t,""),l=d(t,""),o=u(),s=z.useMemo((()=>l.validation.length>0&&l.validation.find((e=>"error"===e.level))),[l]);return z.useEffect((()=>{s?n(t):r(t)}),[n,t,r,s]),i.draft?a(O,{border:!0,padding:2,tone:s?"critical":"positive",children:i.published?a(p,{layout:"default",value:i.published,schemaType:o.get(i.published._type)}):a(b,{})}):null}function J(e){const{translations:t}=e.value,n=s({apiVersion:"v2022-11-21"}),{projectId:i,dataset:l}=m(),o=f(),[c,d]=z.useState([]),u=E((e=>{d((t=>[...t,e]))}),[]),p=E((e=>{d((t=>t.filter((t=>t!==e))))}),[]),h=E((()=>{const e=t.map((e=>({documentId:e.value._ref})));n.request({uri:"/publish/".concat(i,"/").concat(l),method:"POST",body:e}).then((e=>{o.push({status:"success",title:"Success",description:"Bulk publish complete"})})).catch((e=>{console.error(e),o.push({status:"error",title:"Error",description:"Bulk publish failed"})}))}),[t,n,i,l,o]);return(null==t?void 0:t.length)>0?r(j,{space:4,children:[r(j,{space:3,children:[a(_,{weight:"bold",size:1,children:"Bulk publishing"}),r(_,{children:["There"," ",1===t.length?"is 1 document":"are ".concat(t.length," documents"),"."]}),c.length>0?r(_,{weight:"medium",children:[1===c.length?"1 draft has":"".concat(c.length," drafts have")," ","validation issues that must addressed first."]}):a(_,{children:"They are all valid."})]}),a(j,{space:2,children:t.map((e=>a(H,{id:e.value._ref,addId:u,removeId:p},e._key)))}),a(y,{text:"Simultaneously Publish ".concat(1===t.length?"1 Document":"".concat(t.length," Documents")),onClick:h,disabled:Boolean(c.length)})]}):null}const K={supportedLanguages:[],schemaTypes:[],languageField:"language",bulkPublish:!1},Q=h((e=>{const{supportedLanguages:n,schemaTypes:i,languageField:l,bulkPublish:s}=t(t({},K),e);return{name:"@sanity/document-internationalization",form:{components:{input:e=>s&&"root"===e.id&&"translation.metadata"===e.schemaType.name?r(j,{space:5,children:[a(J,t({},e)),e.renderDefault(e)]}):e.renderDefault(e)}},document:{unstable_languageFilter:(e,t)=>{const{schemaType:r,documentId:o}=t;return i.includes(r)?[...e,()=>((e,t)=>a(G,{supportedLanguages:n,schemaType:e,documentId:null!=t?t:"",languageField:l}))(r,o)]:e},badges:(e,t)=>{let{schemaType:a}=t;return i.includes(a)?[e=>function(e,t,n){const a=(null==e?void 0:e.draft)||(null==e?void 0:e.published),r=null==a?void 0:a[n],i=t.find((e=>e.id===r));return i?{label:i.id,title:i.title,color:"primary"}:null}(e,n,l),...e]:e}},schema:{types:[A(i)],templates:(e,t)=>{let{schema:a}=t;return[...e,...i.map((e=>{var t,n;return{id:"".concat(e,"-parameterized"),title:"".concat(null!=(n=null==(t=null==a?void 0:a.get(e))?void 0:t.title)?n:e,": with Language"),schemaType:e,parameters:[{name:"languageId",title:"Language ID",type:"string"}],value:e=>{let{languageId:t}=e;return{[l]:t}}}})),...i.flatMap((e=>n.map((t=>({id:"".concat(e,"-").concat(t.id),title:"".concat(t.title," Lesson"),schemaType:e,value:{[l]:t.id}})))))]}},plugins:[g({languages:n,fieldTypes:[o({name:"reference",type:"reference",to:i.map((e=>({type:e}))),options:{collapsed:!1,filter:e=>{let{parent:t,document:n}=e;if(!t)return null;const a=(Array.isArray(t)?t:[t]).find((e=>e._key));return(null==a?void 0:a._key)?n.schemaTypes?{filter:"_type in $schemaTypes && ".concat(l," == $language"),params:{schemaTypes:n.schemaTypes,language:a._key}}:{filter:"".concat(l," == $language"),params:{language:a._key}}:null}}},{strict:!1})]})]}}));export{Q as documentInternationalization};
2
- //# sourceMappingURL=index.esm.js.map
1
+ function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function t(t){for(var a=1;a<arguments.length;a++){var r=null!=arguments[a]?arguments[a]:{};a%2?e(Object(r),!0).forEach((function(e){n(t,e,r[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):e(Object(r)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(r,e))}))}return t}function n(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var a=n.call(e,t||"default");if("object"!=typeof a)return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}import{jsx as a,jsxs as r,Fragment as i}from"react/jsx-runtime";import{defineType as o,defineField as l,useClient as s,useEditState as c,definePlugin as u}from"sanity";import{internationalizedArray as d}from"sanity-plugin-internationalized-array";import{useToast as p,Button as g,Flex as f,Spinner as m,Text as h,Box as y,Badge as v,useClickOutside as b,Card as T,Stack as _,Popover as O}from"@sanity/ui";import{TranslateIcon as j,SplitVerticalIcon as w,CheckmarkIcon as k,AddIcon as I,CogIcon as P,ChevronRightIcon as S}from"@sanity/icons";import x,{useCallback as C,useState as L}from"react";import{uuid as F}from"@sanity/uuid";import{usePaneRouter as A}from"sanity/desk";import{RouterContext as z}from"sanity/router";import{useListeningQuery as D}from"sanity-plugin-utils";const E="translation.metadata",M="2022-11-27";var N=e=>o({type:"document",name:E,title:"Translation metadata",icon:j,liveEdit:!0,fields:[l({name:"translations",type:"internationalizedArrayReference"}),l({name:"schemaTypes",description:"Used to filter the reference fields above so all translations share the same types.",type:"array",of:[{type:"string"}],options:{list:e},readOnly:e=>{let{value:t}=e;return Boolean(t)}})],preview:{select:{translations:"translations",documentSchemaTypes:"schemaTypes"},prepare(e){const{translations:t,documentSchemaTypes:n}=e,a=1===t.length?"1 Translation":"".concat(t.length," Translations"),r=t.length?t.map((e=>e._key.toUpperCase())).join(", "):"";return{title:a,subtitle:[r?"(".concat(r,")"):null,(null==n?void 0:n.length)?n.map((e=>e.toUpperCase())).join(", "):"No Schemas Defined"].filter(Boolean).join(" ")}}}});function V(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:(e,t)=>e===t;if(e===t)return!0;if(!e||!t)return!1;const a=e.length;if(t.length!==a)return!1;for(let r=0;r<a;r++)if(!n(e[r],t[r]))return!1;return!0}const $=[];const U=(e,t,n)=>function(e,t){let n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};for(const e of $)if(V(t,e.keys,e.equal)){if(n)return;if(Object.prototype.hasOwnProperty.call(e,"error"))throw e.error;if(Object.prototype.hasOwnProperty.call(e,"response"))return e.response;if(!n)throw e.promise}const r={keys:t,equal:a.equal,promise:e(...t).then((e=>r.response=e)).then((()=>{a.lifespan&&a.lifespan>0&&setTimeout((()=>{const e=$.indexOf(r);-1!==e&&$.splice(e,1)}),a.lifespan)})).catch((e=>r.error=e))};if($.push(r),!n)throw r.promise}(e,t,!1,n);function B(e,t){const n=x.useContext(z),{routerPanesState:a,groupIndex:r}=A();return x.useCallback((()=>{if(!n||!e||!t)return;const i=[...a];i.splice(r+1,0,[{id:e,params:{type:t}}]);const o=n.resolvePathFromState({panes:i});n.navigateUrl({path:o})}),[e,t,n,a,r])}function q(e,t,n){return{_key:e,value:{_type:"reference",_ref:t,_weak:!0,_strengthenOnPublish:{type:n}}}}function R(e){var n;const{apiVersion:i=M,index:o,language:l,languageField:c,schemaType:u,documentId:d,disabled:b,current:T,sourceId:_,sourceLanguageId:O,metadata:j,translation:P}=e,S=s({apiVersion:i}),x=p(),L=B(null==(n=null==P?void 0:P.value)?void 0:n._ref,u),A=C((()=>L()),[L]),z=C((async()=>{var e;const n=Boolean(null==j?void 0:j._id),a=S.transaction(),r=d.startsWith("drafts.")?[d,d.replace("drafts.","")]:[d,"drafts.".concat(d)],i=t(t({},await S.fetch("*[_id in $ids]|order(_updatedAt desc)[0]",{ids:r})),{},{_id:"drafts.".concat(F()),[c]:l.id});a.create(i);const s=null!=(e=null==j?void 0:j._id)?e:F(),p=q(l.id,i._id.replace("drafts.",""),u);if(n){const e="translations[".concat(o-1,"]"),t=S.patch(s).setIfMissing({translations:[]}).insert("before",e,[p]);a.patch(t)}else{const e=O?q(O,_,u):null;a.createIfNotExists({_id:s,_type:E,schemaTypes:[u],translations:[p,e].filter(Boolean)})}a.commit().then((()=>x.push({status:"success",title:"Created ".concat(l.title," translation"),description:n?"Updated Translations Metadata":"Created Translations Metadata"}))).catch((e=>(console.error(e),x.push({status:"error",title:"Error creating translation",description:e.message}))))}),[S,d,o,l,c,null==j?void 0:j._id,u,_,O,x]);return a(g,{onClick:P?A:z,mode:T?"default":"bleed",disabled:b||T,children:r(f,{gap:3,align:"center",children:[b?a(m,{}):a(h,{size:2,children:a(P?w:T?k:I,{})}),a(y,{flex:1,children:a(h,{children:l.title})}),a(v,{tone:b||T?"default":"primary",children:l.id})]})})}function W(e){const{id:t}=e,n=B(t,E);return a(g,{disabled:!t,mode:"ghost",text:"Manage Translations",icon:P,onClick:()=>n()})}function G(e){const{apiVersion:t=M,language:n,languageField:r,documentId:i,schemaType:o,source:l,disabled:c=!1}=e,u=s({apiVersion:t}),d=p(),f=x.useCallback((()=>{const e=l?l._id:"draft.".concat(i),t=u.transaction();l||t.createIfNotExists({_id:e,_type:o});const a=u.patch(e).set({[r]:n.id});t.patch(a),t.commit().then((()=>{d.push({title:"Set document language to ".concat(n.title),status:"success"})})).catch((e=>(console.error(e),d.push({title:"Failed to set document language to ".concat(n.title),status:"error"}))))}),[l,i,u,r,n,o,d]);return a(g,{mode:"ghost",text:n.title,icon:S,onClick:()=>f(),disabled:c,justify:"flex-start"})}function H(e){const{apiVersion:t=M,schemaType:n,documentId:o,languageField:l}=e,u=s({apiVersion:t}),d=Array.isArray(e.supportedLanguages)?e.supportedLanguages:U((async()=>"function"==typeof e.supportedLanguages?e.supportedLanguages(u):e.supportedLanguages),[]),[p,f]=L(!1),m=C((()=>f((e=>!e))),[]),[v,w]=L(null),[k,I]=L(null),P=C((()=>f(!1)),[]);b(P,[v,k]);const{data:S,loading:F,error:A}=function(e,t){const{data:n,loading:a,error:r}=D("*[_type == $translationSchema && $id in translations[].value._ref][0]",{params:{id:e,translationSchema:E}});return{data:n,loading:a,error:r}}(o),{draft:z,published:N}=c(o,n),V=z||N,$=null==V?void 0:V[l],B=d.some((e=>e.id===$)),q=x.useMemo((()=>{const e=d.every((e=>e.id&&e.title));return e||console.warn('Not all languages are valid. It should be an array of objects with an "id" and "title" property. Or a function that returns an array of objects with an "id" and "title" property.',d),e}),[d]),H=a(y,{overflow:"auto",children:A?a(T,{tone:"critical",padding:2,children:r(h,{children:["Error: ",A]})}):r(_,{padding:1,space:1,children:[d.length>0?r(i,{children:[d.map(((e,t)=>{var r;return!F&&$&&B?a(R,{index:t,language:e,languageField:l,schemaType:n,documentId:o,disabled:F||!q,current:e.id===$,metadata:S,sourceId:o,sourceLanguageId:$,translation:null==S?void 0:S.translations.find((t=>t._key===e.id))},e.id||e.title||"lang-".concat(t)):a(G,{languageField:l,source:V,documentId:o,schemaType:n,language:e,disabled:null!=(r=!q||(null==S?void 0:S.translations.filter((e=>{var t;return(null==(t=null==e?void 0:e.value)?void 0:t._ref)!==o})).some((t=>t._key===e.id))))&&r},e.id||e.title||"lang-".concat(t))})),F?null:r(i,{children:[q?null:a(T,{tone:"caution",padding:3,children:a(h,{size:1,children:"Not all language objects are valid. See the console."})}),$?null:a(T,{tone:"caution",padding:3,children:r(h,{size:1,children:["Choose a language to ",a("br",{}),"apply to ",a("strong",{children:"this Document"})]})}),$&&!B?a(T,{tone:"caution",padding:3,children:r(h,{size:1,children:["Change the current language value ",a("code",{children:$}),a("br",{}),"to one of the supported languages"]})}):null]})]}):null,a(W,{id:null==S?void 0:S._id})]})});return a(O,{constrainSize:!0,content:H,open:p,portal:!0,ref:I,children:a(g,{text:"Translations",mode:"bleed",disabled:!V,tone:!V||!F&&$&&B?void 0:"caution",icon:j,onClick:m,ref:w,selected:p})})}const J={supportedLanguages:[],schemaTypes:[],languageField:"language",bulkPublish:!1},K=u((e=>{const{supportedLanguages:n,schemaTypes:r,languageField:i,bulkPublish:o}=t(t({},J),e);return{name:"@sanity/document-internationalization",form:{components:{input:e=>o&&"root"===e.id&&e.schemaType.name===E?a(_,{space:5,children:e.renderDefault(e)}):e.renderDefault(e)}},document:{unstable_languageFilter:(e,t)=>{const{schemaType:o,documentId:l}=t;return r.includes(o)?[...e,()=>((e,t)=>a(H,{supportedLanguages:n,schemaType:e,documentId:null!=t?t:"",languageField:i}))(o,l)]:e},badges:(e,t)=>{let{schemaType:a}=t;return r.includes(a)?[e=>function(e,t,n){var a,r;const i=(null==e?void 0:e.draft)||(null==e?void 0:e.published),o=null==i?void 0:i[n];if(!o)return null;const l=Array.isArray(t)?t.find((e=>e.id===o)):null;return{label:null!=(a=null==l?void 0:l.id)?a:String(o),title:null!=(r=null==l?void 0:l.title)?r:void 0,color:"primary"}}(e,n,i),...e]:e}},schema:{types:[N(r)],templates:(e,t)=>{let{schema:a}=t;if(!Array.isArray(n))return e;const o=r.map((e=>{var t,n;return{id:"".concat(e,"-parameterized"),title:"".concat(null!=(n=null==(t=null==a?void 0:a.get(e))?void 0:t.title)?n:e,": with Language"),schemaType:e,parameters:[{name:"languageId",title:"Language ID",type:"string"}],value:e=>{let{languageId:t}=e;return{[i]:t}}}})),l=r.flatMap((e=>n.map((t=>{var n,r;return{id:"".concat(e,"-").concat(t.id),title:"".concat(t.title," ").concat(null!=(r=null==(n=null==a?void 0:a.get(e))?void 0:n.title)?r:e),schemaType:e,value:{[i]:t.id}}}))));return[...e,...o,...l]}},plugins:[d({languages:n,fieldTypes:[l({name:"reference",type:"reference",to:r.map((e=>({type:e}))),options:{collapsed:!1,filter:e=>{let{parent:t,document:n}=e;if(!t)return null;const a=(Array.isArray(t)?t:[t]).find((e=>e._key));return(null==a?void 0:a._key)?n.schemaTypes?{filter:"_type in $schemaTypes && ".concat(i," == $language"),params:{schemaTypes:n.schemaTypes,language:a._key}}:{filter:"".concat(i," == $language"),params:{language:a._key}}:null}}},{strict:!1})]})]}}));export{K as documentInternationalization};//# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/schema/translation/metadata.ts","../src/constants.ts","../src/hooks/useOpenInNewPane.tsx","../src/components/LanguageOption.tsx","../src/components/LanguageManage.tsx","../src/components/LanguagePatch.tsx","../src/components/MenuButton.tsx","../src/hooks/useLanguageMetadata.tsx","../src/components/BulkPublish/DocumentCheck.tsx","../src/components/BulkPublish/index.tsx","../src/plugin.tsx","../src/badges/index.tsx"],"sourcesContent":["import {defineType, defineField} from 'sanity'\nimport {TranslateIcon} from '@sanity/icons'\n\nimport {METADATA_SCHEMA_NAME} from '../../constants'\n\n// TODO: TS having a hard time determining the return type here. Likely a V3 type problem.\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\nexport default (schemaTypes: string[]) =>\n defineType({\n type: 'document',\n name: METADATA_SCHEMA_NAME,\n title: 'Translation metadata',\n icon: TranslateIcon,\n liveEdit: true,\n fields: [\n defineField({\n name: 'translations',\n type: 'internationalizedArrayReference',\n }),\n defineField({\n name: 'schemaTypes',\n description:\n 'Used to filter the reference fields above so all translations share the same types.',\n type: 'array',\n of: [{type: 'string'}],\n options: {list: schemaTypes},\n readOnly: ({value}) => Boolean(value),\n }),\n ],\n preview: {\n select: {\n translations: 'translations',\n documentSchemaTypes: 'schemaTypes',\n },\n prepare(selection) {\n const {translations, documentSchemaTypes} = selection\n const title =\n translations.length === 1 ? `1 Translation` : `${translations.length} Translations`\n const languageKeys = translations.length\n ? translations.map((t: {_key: string}) => t._key.toUpperCase()).join(', ')\n : ``\n const subtitle = [\n languageKeys ? `(${languageKeys})` : null,\n documentSchemaTypes?.length\n ? documentSchemaTypes.map((s: string) => s.toUpperCase()).join(`, `)\n : `No Schemas Defined`,\n ]\n .filter(Boolean)\n .join(` `)\n\n return {\n title,\n subtitle,\n }\n },\n },\n })\n","export const METADATA_SCHEMA_NAME = `translation.metadata`\n","import React from 'react'\nimport {usePaneRouter} from 'sanity/desk'\nimport {RouterContext} from 'sanity/router'\n\nexport function useOpenInNewPane(id?: string, type?: string) {\n const routerContext = React.useContext(RouterContext)\n const {routerPanesState, groupIndex} = usePaneRouter()\n\n const openInNewPane = React.useCallback(() => {\n if (!routerContext || !id || !type) {\n return\n }\n\n const panes = [...routerPanesState]\n panes.splice(groupIndex + 1, 0, [\n {\n id: id,\n params: {type},\n },\n ])\n\n const href = routerContext.resolvePathFromState({panes})\n routerContext.navigateUrl({path: href})\n }, [id, type, routerContext, routerPanesState, groupIndex])\n\n return openInNewPane\n}\n","import React, {useCallback} from 'react'\nimport {useClient} from 'sanity'\nimport {Button, Badge, Box, Flex, Text, useToast, Spinner} from '@sanity/ui'\nimport {uuid} from '@sanity/uuid'\nimport {SplitVerticalIcon, AddIcon, CheckmarkIcon} from '@sanity/icons'\n\nimport {Language, Metadata, TranslationReference} from '../types'\nimport {METADATA_SCHEMA_NAME} from '../constants'\nimport {useOpenInNewPane} from '../hooks/useOpenInNewPane'\n\ntype LanguageOptionProps = {\n language: Language\n languageField: string\n index: number\n schemaType: string\n documentId: string\n disabled: boolean\n current: boolean\n sourceId: string\n sourceLanguageId?: string\n metadata?: Metadata | null\n translation?: TranslationReference\n}\n\nfunction createReference(key: string, ref: string, type: string) {\n return {\n _key: key,\n value: {\n _type: 'reference',\n _ref: ref,\n _weak: true,\n _strengthenOnPublish: {\n type,\n },\n },\n }\n}\n\nexport default function LanguageOption(props: LanguageOptionProps) {\n const {\n index,\n language,\n languageField,\n schemaType,\n documentId,\n disabled,\n current,\n sourceId,\n sourceLanguageId,\n metadata,\n translation,\n } = props\n const client = useClient()\n const toast = useToast()\n\n const open = useOpenInNewPane(translation?.value?._ref, schemaType)\n const handleOpen = useCallback(() => open(), [open])\n\n const handleCreate = useCallback(async () => {\n const metadataExists = Boolean(metadata?._id)\n const transaction = client.transaction()\n\n // 1. Duplicate current document\n // 2. Update language\n // 3. Add to translation metadata\n const documentIds = documentId.startsWith(`drafts.`)\n ? [documentId, documentId.replace(`drafts.`, ``)]\n : [documentId, `drafts.${documentId}`]\n const latestDocument = await client.fetch(`*[_id in $ids]|order(_updatedAt desc)[0]`, {\n ids: documentIds,\n })\n const newTranslationDocument = {\n ...latestDocument,\n _id: `drafts.${uuid()}`,\n [languageField]: language.id,\n }\n\n transaction.create(newTranslationDocument)\n\n const metadataId = metadata?._id ?? uuid()\n const newTranslationReference = createReference(\n language.id,\n newTranslationDocument._id.replace(`drafts.`, ``),\n schemaType\n )\n\n // Create translation metadata document if it doesn't already exist\n if (metadataExists) {\n const path = `translations[${index - 1}]`\n const metadataPatch = client\n .patch(metadataId)\n .setIfMissing({translations: []})\n .insert(`before`, path, [newTranslationReference])\n\n transaction.patch(metadataPatch)\n } else {\n // Source language relies on a field named `language` on the document\n const sourceReference = sourceLanguageId\n ? createReference(sourceLanguageId, sourceId, schemaType)\n : null\n\n transaction.createIfNotExists({\n _id: metadataId,\n _type: METADATA_SCHEMA_NAME,\n schemaTypes: [schemaType],\n translations: [newTranslationReference, sourceReference].filter(Boolean),\n })\n }\n\n transaction\n .commit()\n .then(() => {\n // openDocumentInSidePane(metadataId, `translation.metadata`)\n return toast.push({\n status: 'success',\n title: `Created ${language.title} translation`,\n description: metadataExists\n ? `Updated Translations Metadata`\n : `Created Translations Metadata`,\n })\n })\n .catch((err) => {\n console.error(err)\n\n return toast.push({\n status: 'error',\n title: `Error creating translation`,\n description: err.message,\n })\n })\n }, [\n client,\n documentId,\n index,\n language,\n languageField,\n metadata?._id,\n schemaType,\n sourceId,\n sourceLanguageId,\n toast,\n ])\n\n return (\n <Button\n onClick={translation ? handleOpen : handleCreate}\n mode={current ? `default` : `bleed`}\n disabled={disabled || current}\n >\n <Flex gap={3} align=\"center\">\n {disabled ? (\n <Spinner />\n ) : (\n <Text size={2}>\n {/* eslint-disable-next-line no-nested-ternary */}\n {translation ? <SplitVerticalIcon /> : current ? <CheckmarkIcon /> : <AddIcon />}\n </Text>\n )}\n <Box flex={1}>\n <Text>{language.title}</Text>\n </Box>\n <Badge tone={disabled || current ? `default` : `primary`}>{language.id}</Badge>\n </Flex>\n </Button>\n )\n}\n","import React from 'react'\nimport {CogIcon} from '@sanity/icons'\nimport {Button} from '@sanity/ui'\n\nimport {useOpenInNewPane} from '../hooks/useOpenInNewPane'\nimport {METADATA_SCHEMA_NAME} from '../constants'\n\ntype LanguageManageProps = {\n id?: string\n}\n\nexport default function LanguageManage(props: LanguageManageProps) {\n const {id} = props\n const open = useOpenInNewPane(id, METADATA_SCHEMA_NAME)\n\n return (\n <Button\n disabled={!id}\n mode=\"ghost\"\n text=\"Manage Translations\"\n icon={CogIcon}\n onClick={() => open()}\n />\n )\n}\n","import React from 'react'\nimport {ChevronRightIcon} from '@sanity/icons'\nimport {Button, useToast} from '@sanity/ui'\nimport {SanityDocument, useClient} from 'sanity'\n\nimport {Language} from '../types'\n\ntype LanguagePatchProps = {\n language: Language\n languageField: string\n documentId: string\n schemaType: string\n source: SanityDocument | null\n disabled: boolean\n}\n\nexport default function LanguagePatch(props: LanguagePatchProps) {\n const {language, languageField, documentId, schemaType, source, disabled = false} = props\n const client = useClient()\n const toast = useToast()\n\n const handleClick = React.useCallback(() => {\n const currentId = source ? source._id : `draft.${documentId}`\n const transaction = client.transaction()\n\n if (!source) {\n transaction.createIfNotExists({\n _id: currentId,\n _type: schemaType,\n })\n }\n\n const patch = client.patch(currentId).set({[languageField]: language.id})\n transaction.patch(patch)\n\n transaction\n .commit()\n .then(() => {\n toast.push({\n title: `Set document language to ${language.title}`,\n status: `success`,\n })\n })\n .catch((err) => {\n console.error(err)\n\n return toast.push({\n title: `Failed to set document language to ${language.title}`,\n status: `error`,\n })\n })\n }, [source, documentId, client, languageField, language, schemaType, toast])\n\n return (\n <Button\n mode=\"ghost\"\n text={language.title}\n icon={ChevronRightIcon}\n onClick={() => handleClick()}\n disabled={disabled}\n justify=\"flex-start\"\n />\n )\n}\n","import React, {useCallback, useState} from 'react'\nimport {Text, Card, useClickOutside, Stack, Popover, Button, Box} from '@sanity/ui'\nimport {TranslateIcon} from '@sanity/icons'\nimport {useEditState} from 'sanity'\n\nimport {Language} from '../types'\nimport LanguageOption from './LanguageOption'\nimport {useTranslationMetadata} from '../hooks/useLanguageMetadata'\nimport LanguageManage from './LanguageManage'\nimport LanguagePatch from './LanguagePatch'\n\ntype MenuButtonProps = {\n supportedLanguages: Language[]\n schemaType: string\n documentId: string\n languageField: string\n}\n\nexport default function MenuButton(props: MenuButtonProps) {\n const {supportedLanguages, schemaType, documentId, languageField} = props\n\n const [open, setOpen] = useState(false)\n const handleClick = useCallback(() => setOpen((o) => !o), [])\n const [button, setButton] = useState<HTMLElement | null>(null)\n const [popover, setPopover] = useState<HTMLElement | null>(null)\n const handleClickOutside = useCallback(() => setOpen(false), [])\n useClickOutside(handleClickOutside, [button, popover])\n const {data: metadata, loading, error} = useTranslationMetadata(documentId, schemaType)\n const {draft, published} = useEditState(documentId, schemaType)\n const source = draft || published\n\n const sourceLanguageId = source?.[languageField] as string | undefined\n const sourceLanguageIsValid = supportedLanguages.some((l) => l.id === sourceLanguageId)\n\n const content = (\n <Box overflow=\"auto\">\n {error ? (\n <Card tone=\"critical\" padding={2}>\n <Text>Error: {error}</Text>\n </Card>\n ) : (\n <Stack padding={1} space={1}>\n {supportedLanguages.length > 0 ? (\n <>\n {supportedLanguages.map((language, langIndex) =>\n !loading && sourceLanguageId && sourceLanguageIsValid ? (\n // Button to duplicate this document to a new translation\n // And either create or update the metadata document\n <LanguageOption\n key={language.id}\n index={langIndex}\n language={language}\n languageField={languageField}\n schemaType={schemaType}\n documentId={documentId}\n disabled={loading}\n current={language.id === sourceLanguageId}\n metadata={metadata}\n sourceId={documentId}\n sourceLanguageId={sourceLanguageId}\n translation={metadata?.translations.find((t) => t._key === language.id)}\n />\n ) : (\n // Button to set a language field on *this* document\n <LanguagePatch\n key={language.id}\n languageField={languageField}\n source={source}\n documentId={documentId}\n schemaType={schemaType}\n language={language}\n // Only allow language patch change to:\n // - Keys not in metadata\n // - The key of this document in the metadata\n disabled={\n metadata?.translations\n .filter((t) => t?.value?._ref !== documentId)\n .some((t) => t._key === language.id) ?? false\n }\n />\n )\n )}\n {/* Once metadata is loaded, there may be issues */}\n {loading ? null : (\n <>\n {/* Current document has no language field */}\n {sourceLanguageId ? null : (\n <Card tone=\"caution\" padding={3}>\n <Text size={1}>\n Choose a language to <br />\n apply to <strong>this Document</strong>\n </Text>\n </Card>\n )}\n {/* Current document has an invalid language field */}\n {sourceLanguageId && !sourceLanguageIsValid ? (\n <Card tone=\"caution\" padding={3}>\n <Text size={1}>\n Change the current language value <code>{sourceLanguageId}</code>\n <br />\n to one of the supported languages\n </Text>\n </Card>\n ) : null}\n </>\n )}\n </>\n ) : null}\n <LanguageManage id={metadata?._id} />\n </Stack>\n )}\n </Box>\n )\n\n return (\n <Popover constrainSize content={content} open={open} portal ref={setPopover}>\n <Button\n text=\"Translations\"\n mode=\"bleed\"\n disabled={!source}\n tone={\n !source || (!loading && sourceLanguageId && sourceLanguageIsValid) ? undefined : `caution`\n }\n icon={TranslateIcon}\n onClick={handleClick}\n ref={setButton}\n selected={open}\n />\n </Popover>\n )\n}\n","import React from 'react'\nimport {useListeningQuery} from 'sanity-plugin-utils'\nimport {METADATA_SCHEMA_NAME} from '../constants'\n\nimport {Metadata} from '../types'\n\nexport function useTranslationMetadata(\n id: string,\n schemaType: string\n): {\n data: Metadata | null\n loading: boolean\n error: boolean\n} {\n const query = `*[_type == $translationSchema && $id in translations[].value._ref][0]`\n const {data, loading, error} = useListeningQuery<Metadata>(query, {\n params: {id, translationSchema: METADATA_SCHEMA_NAME},\n })\n\n return {data, loading, error}\n}\n","import React from 'react'\nimport {Card, Spinner} from '@sanity/ui'\nimport {\n useEditState,\n useValidationStatus,\n SanityPreview as Preview,\n SchemaType,\n useSchema,\n} from 'sanity'\n\ntype DocumentCheckProps = {\n id: string\n addId: (id: string) => void\n removeId: (id: string) => void\n}\n\n// Check if the document has a draft\n// Check if that draft is valid\n// Report back to parent that it can be added to bulk publish\nexport default function DocumentCheck(props: DocumentCheckProps) {\n const {id, addId, removeId} = props\n const editState = useEditState(id, ``)\n const validationStatus = useValidationStatus(id, ``)\n const schema = useSchema()\n\n const validationHasErrors = React.useMemo(() => {\n return (\n validationStatus.validation.length > 0 &&\n validationStatus.validation.find((item) => item.level === 'error')\n )\n }, [validationStatus])\n\n React.useEffect(() => {\n if (validationHasErrors) {\n addId(id)\n } else {\n removeId(id)\n }\n }, [addId, id, removeId, validationHasErrors])\n\n // We only care about drafts\n if (!editState.draft) {\n return null\n }\n\n return (\n <Card border padding={2} tone={validationHasErrors ? `critical` : `positive`}>\n {editState.published ? (\n <Preview\n layout=\"default\"\n value={editState.published}\n schemaType={schema.get(editState.published._type) as SchemaType}\n />\n ) : (\n <Spinner />\n )}\n </Card>\n )\n}\n","import React, {useCallback} from 'react'\nimport {Box, Text, Stack, Button, useToast} from '@sanity/ui'\nimport {\n InputProps,\n Reference,\n SanityDocument,\n KeyedObject,\n TypedObject,\n useClient,\n useWorkspace,\n} from 'sanity'\nimport DocumentCheck from './DocumentCheck'\n\nexport type TranslationReference = KeyedObject & TypedObject & {value: Reference}\n\nexport type TranslationMetadataDocument = SanityDocument & {\n translations: TranslationReference[]\n schemaTypes: string[]\n}\n\nexport default function BulkPublish(props: InputProps) {\n const {translations} = props.value as TranslationMetadataDocument\n const client = useClient({apiVersion: `v2022-11-21`})\n const {projectId, dataset} = useWorkspace()\n const toast = useToast()\n const [invalidIds, setInvalidIds] = React.useState<string[]>([])\n\n const addId = useCallback((id: string) => {\n setInvalidIds((ids) => [...ids, id])\n }, [])\n\n const removeId = useCallback((id: string) => {\n setInvalidIds((ids) => ids.filter((i) => i !== id))\n }, [])\n\n const handleBulkPublish = useCallback(() => {\n const body = translations.map((translation) => ({documentId: translation.value._ref}))\n client\n .request({\n uri: `/publish/${projectId}/${dataset}`,\n method: 'POST',\n body,\n })\n .then((res) => {\n toast.push({\n status: 'success',\n title: 'Success',\n description: 'Bulk publish complete',\n })\n })\n .catch((err) => {\n console.error(err)\n toast.push({\n status: 'error',\n title: 'Error',\n description: 'Bulk publish failed',\n })\n })\n }, [translations, client, projectId, dataset, toast])\n\n // TODO: Hide all this if none of the documents have drafts\n return translations?.length > 0 ? (\n <Stack space={4}>\n <Stack space={3}>\n <Text weight=\"bold\" size={1}>\n Bulk publishing\n </Text>\n <Text>\n There{' '}\n {translations.length === 1 ? `is 1 document` : `are ${translations.length} documents`}.\n </Text>\n {invalidIds.length > 0 ? (\n <Text weight=\"medium\">\n {invalidIds.length === 1 ? `1 draft has` : `${invalidIds.length} drafts have`}{' '}\n validation issues that must addressed first.\n </Text>\n ) : (\n <Text>They are all valid.</Text>\n )}\n </Stack>\n <Stack space={2}>\n {translations.map((translation) => (\n <DocumentCheck\n key={translation._key}\n id={translation.value._ref}\n addId={addId}\n removeId={removeId}\n />\n ))}\n </Stack>\n <Button\n text={`Simultaneously Publish ${\n translations.length === 1 ? `1 Document` : `${translations.length} Documents`\n }`}\n onClick={handleBulkPublish}\n disabled={Boolean(invalidIds.length)}\n />\n </Stack>\n ) : null\n}\n","import React from 'react'\nimport {definePlugin, defineField} from 'sanity'\nimport {internationalizedArray} from 'sanity-plugin-internationalized-array'\nimport {Stack} from '@sanity/ui'\n\nimport metadata from './schema/translation/metadata'\nimport MenuButton from './components/MenuButton'\nimport {PluginConfig} from './types'\nimport {LanguageBadge} from './badges'\nimport {METADATA_SCHEMA_NAME} from './constants'\nimport BulkPublish from './components/BulkPublish'\n\nconst DEFAULT_CONFIG = {\n supportedLanguages: [],\n schemaTypes: [],\n languageField: `language`,\n bulkPublish: false,\n}\n\nexport const documentInternationalization = definePlugin<PluginConfig>((config) => {\n const {supportedLanguages, schemaTypes, languageField, bulkPublish} = {\n ...DEFAULT_CONFIG,\n ...config,\n }\n\n const renderLanguageFilter = (schemaType: string, documentId?: string) => {\n return (\n <MenuButton\n supportedLanguages={supportedLanguages}\n schemaType={schemaType}\n documentId={documentId ?? ``}\n languageField={languageField}\n />\n )\n }\n\n return {\n name: '@sanity/document-internationalization',\n\n // Adds:\n // - A bulk-publishing UI component to the form\n // - Will only work for projects on a compatible plan\n form: {\n components: {\n input: (props) => {\n if (\n bulkPublish &&\n props.id === 'root' &&\n props.schemaType.name === METADATA_SCHEMA_NAME\n ) {\n return (\n <Stack space={5}>\n <BulkPublish {...props} />\n {props.renderDefault(props)}\n </Stack>\n )\n }\n\n return props.renderDefault(props)\n },\n },\n },\n\n // Adds:\n // - The `Translations` dropdown to the editing form\n // - `Badges` to documents with a language value\n document: {\n unstable_languageFilter: (prev, ctx) => {\n const {schemaType, documentId} = ctx\n\n return schemaTypes.includes(schemaType)\n ? [...prev, () => renderLanguageFilter(schemaType, documentId)]\n : prev\n },\n badges: (prev, {schemaType}) => {\n if (!schemaTypes.includes(schemaType)) {\n return prev\n }\n\n return [(props) => LanguageBadge(props, supportedLanguages, languageField), ...prev]\n },\n },\n\n // Adds:\n // - The `Translations metadata` document type to the schema\n schema: {\n // Create the metadata document type\n types: [metadata(schemaTypes)],\n\n // For every schema type this plugin is enabled on\n // Create an initial value template to set the language\n templates: (prev, {schema}) => {\n const parameterizedTemplates = schemaTypes.map((schemaType) => ({\n id: `${schemaType}-parameterized`,\n title: `${schema?.get(schemaType)?.title ?? schemaType}: with Language`,\n schemaType,\n parameters: [{name: `languageId`, title: `Language ID`, type: `string`}],\n value: ({languageId}: {languageId: string}) => ({\n [languageField]: languageId,\n }),\n }))\n\n const staticTemplates = schemaTypes.flatMap((schemaType) => {\n return supportedLanguages.map((language) => ({\n id: `${schemaType}-${language.id}`,\n title: `${language.title} Lesson`,\n schemaType,\n value: {\n [languageField]: language.id,\n },\n }))\n })\n\n return [...prev, ...parameterizedTemplates, ...staticTemplates]\n },\n },\n\n // Uses:\n // - `sanity-plugin-internationalized-array` to maintain the translations array\n plugins: [\n // Translation metadata stores its references using this plugin\n // It cuts down on attribute usage and gives UI conveniences to add new translations\n internationalizedArray({\n languages: supportedLanguages,\n fieldTypes: [\n // TODO: The plugin should allow this kind of input\n // @ts-ignore\n defineField(\n {\n name: 'reference',\n type: 'reference',\n to: schemaTypes.map((type) => ({type: type})),\n // TODO: Add a validation rule to *ensure* the document's language matches the array key\n // Reference filters don't actually enforce validation!\n // validation: (Rule) => Rule.custom(),\n options: {\n collapsed: false,\n // TODO: Update type once it knows the values of this filter\n // @ts-ignore\n filter: ({parent, document}) => {\n if (!parent) return null\n\n // I'm not sure in what instance there's an array of parents\n // But the Type suggests it's possible\n const parentArray = Array.isArray(parent) ? parent : [parent]\n const language = parentArray.find((p) => p._key)\n\n if (!language?._key) return null\n\n if (document.schemaTypes) {\n return {\n filter: `_type in $schemaTypes && ${languageField} == $language`,\n params: {schemaTypes: document.schemaTypes, language: language._key},\n }\n }\n\n return {\n filter: `${languageField} == $language`,\n params: {language: language._key},\n }\n },\n },\n },\n {strict: false}\n ),\n ],\n }),\n ],\n }\n})\n","import {DocumentBadgeDescription, DocumentBadgeProps} from 'sanity'\n\nimport {Language} from '../types'\n\nexport function LanguageBadge(\n props: DocumentBadgeProps,\n supportedLanguages: Language[],\n languageField: string\n): DocumentBadgeDescription | null {\n const source = props?.draft || props?.published\n const languageId = source?.[languageField]\n const language = supportedLanguages.find((l) => l.id === languageId)\n\n if (!language) {\n return null\n }\n\n return {\n label: language.id,\n title: language.title,\n color: `primary`,\n }\n}\n"],"names":["metadata","schemaTypes","defineType","type","name","title","icon","TranslateIcon","liveEdit","fields","defineField","description","of","options","list","readOnly","_ref","value","Boolean","preview","select","translations","documentSchemaTypes","prepare","selection","length","languageKeys","map","t","_key","toUpperCase","join","subtitle","s","filter","useOpenInNewPane","id","routerContext","React","useContext","RouterContext","routerPanesState","groupIndex","usePaneRouter","useCallback","panes","splice","params","href","resolvePathFromState","navigateUrl","path","createReference","key","ref","_type","_weak","_strengthenOnPublish","LanguageOption","props","_a","index","language","languageField","schemaType","documentId","disabled","current","sourceId","sourceLanguageId","translation","client","useClient","toast","useToast","open","handleOpen","handleCreate","async","metadataExists","_id","transaction","documentIds","startsWith","replace","concat","newTranslationDocument","fetch","ids","uuid","create","metadataId","newTranslationReference","metadataPatch","patch","setIfMissing","insert","sourceReference","createIfNotExists","commit","then","push","status","catch","err","console","error","message","jsx","Button","onClick","mode","children","jsxs","Flex","gap","align","Spinner","Text","size","SplitVerticalIcon","CheckmarkIcon","AddIcon","Box","flex","Badge","tone","LanguageManage","text","CogIcon","LanguagePatch","source","handleClick","currentId","set","ChevronRightIcon","justify","MenuButton","supportedLanguages","setOpen","useState","o","button","setButton","popover","setPopover","handleClickOutside","useClickOutside","data","loading","useListeningQuery","translationSchema","useTranslationMetadata","draft","published","useEditState","sourceLanguageIsValid","some","l","content","overflow","Card","padding","Stack","space","Fragment","langIndex","find","Popover","constrainSize","portal","selected","DocumentCheck","addId","removeId","editState","validationStatus","useValidationStatus","schema","useSchema","validationHasErrors","useMemo","validation","item","level","useEffect","border","Preview","layout","get","BulkPublish","apiVersion","projectId","dataset","useWorkspace","invalidIds","setInvalidIds","i","handleBulkPublish","body","request","uri","method","res","weight","DEFAULT_CONFIG","bulkPublish","documentInternationalization","definePlugin","config","form","components","input","_objectSpread","renderDefault","document","unstable_languageFilter","prev","ctx","includes","renderLanguageFilter","badges","_ref2","languageId","label","color","LanguageBadge","types","templates","_ref3","_b","parameters","_ref4","flatMap","plugins","internationalizedArray","languages","fieldTypes","to","collapsed","_ref5","parent","Array","isArray","p","strict"],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
package/lib/index.js CHANGED
@@ -1,2 +1 @@
1
- "use strict";function e(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function t(t){for(var n=1;n<arguments.length;n++){var s=null!=arguments[n]?arguments[n]:{};n%2?e(Object(s),!0).forEach((function(e){a(t,e,s[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(s)):e(Object(s)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(s,e))}))}return t}function a(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}Object.defineProperty(exports,"__esModule",{value:!0});var n=require("react/jsx-runtime"),s=require("sanity"),r=require("sanity-plugin-internationalized-array"),i=require("@sanity/ui"),l=require("@sanity/icons"),o=require("react"),c=require("@sanity/uuid"),u=require("sanity/desk"),d=require("sanity/router"),p=require("sanity-plugin-utils");function h(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var g=h(o);var m=e=>s.defineType({type:"document",name:"translation.metadata",title:"Translation metadata",icon:l.TranslateIcon,liveEdit:!0,fields:[s.defineField({name:"translations",type:"internationalizedArrayReference"}),s.defineField({name:"schemaTypes",description:"Used to filter the reference fields above so all translations share the same types.",type:"array",of:[{type:"string"}],options:{list:e},readOnly:e=>{let{value:t}=e;return Boolean(t)}})],preview:{select:{translations:"translations",documentSchemaTypes:"schemaTypes"},prepare(e){const{translations:t,documentSchemaTypes:a}=e,n=1===t.length?"1 Translation":"".concat(t.length," Translations"),s=t.length?t.map((e=>e._key.toUpperCase())).join(", "):"";return{title:n,subtitle:[s?"(".concat(s,")"):null,(null==a?void 0:a.length)?a.map((e=>e.toUpperCase())).join(", "):"No Schemas Defined"].filter(Boolean).join(" ")}}}});function f(e,t){const a=g.default.useContext(d.RouterContext),{routerPanesState:n,groupIndex:s}=u.usePaneRouter();return g.default.useCallback((()=>{if(!a||!e||!t)return;const r=[...n];r.splice(s+1,0,[{id:e,params:{type:t}}]);const i=a.resolvePathFromState({panes:r});a.navigateUrl({path:i})}),[e,t,a,n,s])}function y(e,t,a){return{_key:e,value:{_type:"reference",_ref:t,_weak:!0,_strengthenOnPublish:{type:a}}}}function x(e){var a;const{index:r,language:u,languageField:d,schemaType:p,documentId:h,disabled:g,current:m,sourceId:x,sourceLanguageId:b,metadata:j,translation:v}=e,T=s.useClient(),k=i.useToast(),_=f(null==(a=null==v?void 0:v.value)?void 0:a._ref,p),C=o.useCallback((()=>_()),[_]),I=o.useCallback((async()=>{var e;const a=Boolean(null==j?void 0:j._id),n=T.transaction(),s=h.startsWith("drafts.")?[h,h.replace("drafts.","")]:[h,"drafts.".concat(h)],i=t(t({},await T.fetch("*[_id in $ids]|order(_updatedAt desc)[0]",{ids:s})),{},{_id:"drafts.".concat(c.uuid()),[d]:u.id});n.create(i);const l=null!=(e=null==j?void 0:j._id)?e:c.uuid(),o=y(u.id,i._id.replace("drafts.",""),p);if(a){const e="translations[".concat(r-1,"]"),t=T.patch(l).setIfMissing({translations:[]}).insert("before",e,[o]);n.patch(t)}else{const e=b?y(b,x,p):null;n.createIfNotExists({_id:l,_type:"translation.metadata",schemaTypes:[p],translations:[o,e].filter(Boolean)})}n.commit().then((()=>k.push({status:"success",title:"Created ".concat(u.title," translation"),description:a?"Updated Translations Metadata":"Created Translations Metadata"}))).catch((e=>(console.error(e),k.push({status:"error",title:"Error creating translation",description:e.message}))))}),[T,h,r,u,d,null==j?void 0:j._id,p,x,b,k]);return n.jsx(i.Button,{onClick:v?C:I,mode:m?"default":"bleed",disabled:g||m,children:n.jsxs(i.Flex,{gap:3,align:"center",children:[g?n.jsx(i.Spinner,{}):n.jsx(i.Text,{size:2,children:v?n.jsx(l.SplitVerticalIcon,{}):m?n.jsx(l.CheckmarkIcon,{}):n.jsx(l.AddIcon,{})}),n.jsx(i.Box,{flex:1,children:n.jsx(i.Text,{children:u.title})}),n.jsx(i.Badge,{tone:g||m?"default":"primary",children:u.id})]})})}function b(e){const{id:t}=e,a=f(t,"translation.metadata");return n.jsx(i.Button,{disabled:!t,mode:"ghost",text:"Manage Translations",icon:l.CogIcon,onClick:()=>a()})}function j(e){const{language:t,languageField:a,documentId:r,schemaType:o,source:c,disabled:u=!1}=e,d=s.useClient(),p=i.useToast(),h=g.default.useCallback((()=>{const e=c?c._id:"draft.".concat(r),n=d.transaction();c||n.createIfNotExists({_id:e,_type:o});const s=d.patch(e).set({[a]:t.id});n.patch(s),n.commit().then((()=>{p.push({title:"Set document language to ".concat(t.title),status:"success"})})).catch((e=>(console.error(e),p.push({title:"Failed to set document language to ".concat(t.title),status:"error"}))))}),[c,r,d,a,t,o,p]);return n.jsx(i.Button,{mode:"ghost",text:t.title,icon:l.ChevronRightIcon,onClick:()=>h(),disabled:u,justify:"flex-start"})}function v(e){const{supportedLanguages:t,schemaType:a,documentId:r,languageField:c}=e,[u,d]=o.useState(!1),h=o.useCallback((()=>d((e=>!e))),[]),[g,m]=o.useState(null),[f,y]=o.useState(null),v=o.useCallback((()=>d(!1)),[]);i.useClickOutside(v,[g,f]);const{data:T,loading:k,error:_}=function(e,t){const{data:a,loading:n,error:s}=p.useListeningQuery("*[_type == $translationSchema && $id in translations[].value._ref][0]",{params:{id:e,translationSchema:"translation.metadata"}});return{data:a,loading:n,error:s}}(r),{draft:C,published:I}=s.useEditState(r,a),S=C||I,O=null==S?void 0:S[c],P=t.some((e=>e.id===O)),F=n.jsx(i.Box,{overflow:"auto",children:_?n.jsx(i.Card,{tone:"critical",padding:2,children:n.jsxs(i.Text,{children:["Error: ",_]})}):n.jsxs(i.Stack,{padding:1,space:1,children:[t.length>0?n.jsxs(n.Fragment,{children:[t.map(((e,t)=>{var s;return!k&&O&&P?n.jsx(x,{index:t,language:e,languageField:c,schemaType:a,documentId:r,disabled:k,current:e.id===O,metadata:T,sourceId:r,sourceLanguageId:O,translation:null==T?void 0:T.translations.find((t=>t._key===e.id))},e.id):n.jsx(j,{languageField:c,source:S,documentId:r,schemaType:a,language:e,disabled:null!=(s=null==T?void 0:T.translations.filter((e=>{var t;return(null==(t=null==e?void 0:e.value)?void 0:t._ref)!==r})).some((t=>t._key===e.id)))&&s},e.id)})),k?null:n.jsxs(n.Fragment,{children:[O?null:n.jsx(i.Card,{tone:"caution",padding:3,children:n.jsxs(i.Text,{size:1,children:["Choose a language to ",n.jsx("br",{}),"apply to ",n.jsx("strong",{children:"this Document"})]})}),O&&!P?n.jsx(i.Card,{tone:"caution",padding:3,children:n.jsxs(i.Text,{size:1,children:["Change the current language value ",n.jsx("code",{children:O}),n.jsx("br",{}),"to one of the supported languages"]})}):null]})]}):null,n.jsx(b,{id:null==T?void 0:T._id})]})});return n.jsx(i.Popover,{constrainSize:!0,content:F,open:u,portal:!0,ref:y,children:n.jsx(i.Button,{text:"Translations",mode:"bleed",disabled:!S,tone:!S||!k&&O&&P?void 0:"caution",icon:l.TranslateIcon,onClick:h,ref:m,selected:u})})}function T(e){const{id:t,addId:a,removeId:r}=e,l=s.useEditState(t,""),o=s.useValidationStatus(t,""),c=s.useSchema(),u=g.default.useMemo((()=>o.validation.length>0&&o.validation.find((e=>"error"===e.level))),[o]);return g.default.useEffect((()=>{u?a(t):r(t)}),[a,t,r,u]),l.draft?n.jsx(i.Card,{border:!0,padding:2,tone:u?"critical":"positive",children:l.published?n.jsx(s.SanityPreview,{layout:"default",value:l.published,schemaType:c.get(l.published._type)}):n.jsx(i.Spinner,{})}):null}function k(e){const{translations:t}=e.value,a=s.useClient({apiVersion:"v2022-11-21"}),{projectId:r,dataset:l}=s.useWorkspace(),c=i.useToast(),[u,d]=g.default.useState([]),p=o.useCallback((e=>{d((t=>[...t,e]))}),[]),h=o.useCallback((e=>{d((t=>t.filter((t=>t!==e))))}),[]),m=o.useCallback((()=>{const e=t.map((e=>({documentId:e.value._ref})));a.request({uri:"/publish/".concat(r,"/").concat(l),method:"POST",body:e}).then((e=>{c.push({status:"success",title:"Success",description:"Bulk publish complete"})})).catch((e=>{console.error(e),c.push({status:"error",title:"Error",description:"Bulk publish failed"})}))}),[t,a,r,l,c]);return(null==t?void 0:t.length)>0?n.jsxs(i.Stack,{space:4,children:[n.jsxs(i.Stack,{space:3,children:[n.jsx(i.Text,{weight:"bold",size:1,children:"Bulk publishing"}),n.jsxs(i.Text,{children:["There"," ",1===t.length?"is 1 document":"are ".concat(t.length," documents"),"."]}),u.length>0?n.jsxs(i.Text,{weight:"medium",children:[1===u.length?"1 draft has":"".concat(u.length," drafts have")," ","validation issues that must addressed first."]}):n.jsx(i.Text,{children:"They are all valid."})]}),n.jsx(i.Stack,{space:2,children:t.map((e=>n.jsx(T,{id:e.value._ref,addId:p,removeId:h},e._key)))}),n.jsx(i.Button,{text:"Simultaneously Publish ".concat(1===t.length?"1 Document":"".concat(t.length," Documents")),onClick:m,disabled:Boolean(u.length)})]}):null}const _={supportedLanguages:[],schemaTypes:[],languageField:"language",bulkPublish:!1},C=s.definePlugin((e=>{const{supportedLanguages:a,schemaTypes:l,languageField:o,bulkPublish:c}=t(t({},_),e);return{name:"@sanity/document-internationalization",form:{components:{input:e=>c&&"root"===e.id&&"translation.metadata"===e.schemaType.name?n.jsxs(i.Stack,{space:5,children:[n.jsx(k,t({},e)),e.renderDefault(e)]}):e.renderDefault(e)}},document:{unstable_languageFilter:(e,t)=>{const{schemaType:s,documentId:r}=t;return l.includes(s)?[...e,()=>((e,t)=>n.jsx(v,{supportedLanguages:a,schemaType:e,documentId:null!=t?t:"",languageField:o}))(s,r)]:e},badges:(e,t)=>{let{schemaType:n}=t;return l.includes(n)?[e=>function(e,t,a){const n=(null==e?void 0:e.draft)||(null==e?void 0:e.published),s=null==n?void 0:n[a],r=t.find((e=>e.id===s));return r?{label:r.id,title:r.title,color:"primary"}:null}(e,a,o),...e]:e}},schema:{types:[m(l)],templates:(e,t)=>{let{schema:n}=t;return[...e,...l.map((e=>{var t,a;return{id:"".concat(e,"-parameterized"),title:"".concat(null!=(a=null==(t=null==n?void 0:n.get(e))?void 0:t.title)?a:e,": with Language"),schemaType:e,parameters:[{name:"languageId",title:"Language ID",type:"string"}],value:e=>{let{languageId:t}=e;return{[o]:t}}}})),...l.flatMap((e=>a.map((t=>({id:"".concat(e,"-").concat(t.id),title:"".concat(t.title," Lesson"),schemaType:e,value:{[o]:t.id}})))))]}},plugins:[r.internationalizedArray({languages:a,fieldTypes:[s.defineField({name:"reference",type:"reference",to:l.map((e=>({type:e}))),options:{collapsed:!1,filter:e=>{let{parent:t,document:a}=e;if(!t)return null;const n=(Array.isArray(t)?t:[t]).find((e=>e._key));return(null==n?void 0:n._key)?a.schemaTypes?{filter:"_type in $schemaTypes && ".concat(o," == $language"),params:{schemaTypes:a.schemaTypes,language:n._key}}:{filter:"".concat(o," == $language"),params:{language:n._key}}:null}}},{strict:!1})]})]}}));exports.documentInternationalization=C;
2
- //# sourceMappingURL=index.js.map
1
+ "use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function t(t){for(var a=1;a<arguments.length;a++){var r=null!=arguments[a]?arguments[a]:{};a%2?e(Object(r),!0).forEach((function(e){n(t,e,r[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):e(Object(r)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(r,e))}))}return t}function n(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var a=n.call(e,t||"default");if("object"!=typeof a)return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}Object.defineProperty(exports,"__esModule",{value:!0});var a=require("react/jsx-runtime"),r=require("sanity"),i=require("sanity-plugin-internationalized-array"),s=require("@sanity/ui"),l=require("@sanity/icons"),o=require("react"),u=require("@sanity/uuid"),c=require("sanity/desk"),d=require("sanity/router"),p=require("sanity-plugin-utils");function g(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var f=g(o);const h="translation.metadata",y="2022-11-27";var m=e=>r.defineType({type:"document",name:h,title:"Translation metadata",icon:l.TranslateIcon,liveEdit:!0,fields:[r.defineField({name:"translations",type:"internationalizedArrayReference"}),r.defineField({name:"schemaTypes",description:"Used to filter the reference fields above so all translations share the same types.",type:"array",of:[{type:"string"}],options:{list:e},readOnly:e=>{let{value:t}=e;return Boolean(t)}})],preview:{select:{translations:"translations",documentSchemaTypes:"schemaTypes"},prepare(e){const{translations:t,documentSchemaTypes:n}=e,a=1===t.length?"1 Translation":"".concat(t.length," Translations"),r=t.length?t.map((e=>e._key.toUpperCase())).join(", "):"";return{title:a,subtitle:[r?"(".concat(r,")"):null,(null==n?void 0:n.length)?n.map((e=>e.toUpperCase())).join(", "):"No Schemas Defined"].filter(Boolean).join(" ")}}}});function v(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:(e,t)=>e===t;if(e===t)return!0;if(!e||!t)return!1;const a=e.length;if(t.length!==a)return!1;for(let r=0;r<a;r++)if(!n(e[r],t[r]))return!1;return!0}const b=[];const j=(e,t,n)=>function(e,t){let n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};for(const e of b)if(v(t,e.keys,e.equal)){if(n)return;if(Object.prototype.hasOwnProperty.call(e,"error"))throw e.error;if(Object.prototype.hasOwnProperty.call(e,"response"))return e.response;if(!n)throw e.promise}const r={keys:t,equal:a.equal,promise:e(...t).then((e=>r.response=e)).then((()=>{a.lifespan&&a.lifespan>0&&setTimeout((()=>{const e=b.indexOf(r);-1!==e&&b.splice(e,1)}),a.lifespan)})).catch((e=>r.error=e))};if(b.push(r),!n)throw r.promise}(e,t,!1,n);function x(e,t){const n=f.default.useContext(d.RouterContext),{routerPanesState:a,groupIndex:r}=c.usePaneRouter();return f.default.useCallback((()=>{if(!n||!e||!t)return;const i=[...a];i.splice(r+1,0,[{id:e,params:{type:t}}]);const s=n.resolvePathFromState({panes:i});n.navigateUrl({path:s})}),[e,t,n,a,r])}function T(e,t,n){return{_key:e,value:{_type:"reference",_ref:t,_weak:!0,_strengthenOnPublish:{type:n}}}}function _(e){var n;const{apiVersion:i=y,index:c,language:d,languageField:p,schemaType:g,documentId:f,disabled:m,current:v,sourceId:b,sourceLanguageId:j,metadata:_,translation:k}=e,C=r.useClient({apiVersion:i}),O=s.useToast(),I=x(null==(n=null==k?void 0:k.value)?void 0:n._ref,g),S=o.useCallback((()=>I()),[I]),w=o.useCallback((async()=>{var e;const n=Boolean(null==_?void 0:_._id),a=C.transaction(),r=f.startsWith("drafts.")?[f,f.replace("drafts.","")]:[f,"drafts.".concat(f)],i=t(t({},await C.fetch("*[_id in $ids]|order(_updatedAt desc)[0]",{ids:r})),{},{_id:"drafts.".concat(u.uuid()),[p]:d.id});a.create(i);const s=null!=(e=null==_?void 0:_._id)?e:u.uuid(),l=T(d.id,i._id.replace("drafts.",""),g);if(n){const e="translations[".concat(c-1,"]"),t=C.patch(s).setIfMissing({translations:[]}).insert("before",e,[l]);a.patch(t)}else{const e=j?T(j,b,g):null;a.createIfNotExists({_id:s,_type:h,schemaTypes:[g],translations:[l,e].filter(Boolean)})}a.commit().then((()=>O.push({status:"success",title:"Created ".concat(d.title," translation"),description:n?"Updated Translations Metadata":"Created Translations Metadata"}))).catch((e=>(console.error(e),O.push({status:"error",title:"Error creating translation",description:e.message}))))}),[C,f,c,d,p,null==_?void 0:_._id,g,b,j,O]);return a.jsx(s.Button,{onClick:k?S:w,mode:v?"default":"bleed",disabled:m||v,children:a.jsxs(s.Flex,{gap:3,align:"center",children:[m?a.jsx(s.Spinner,{}):a.jsx(s.Text,{size:2,children:k?a.jsx(l.SplitVerticalIcon,{}):v?a.jsx(l.CheckmarkIcon,{}):a.jsx(l.AddIcon,{})}),a.jsx(s.Box,{flex:1,children:a.jsx(s.Text,{children:d.title})}),a.jsx(s.Badge,{tone:m||v?"default":"primary",children:d.id})]})})}function k(e){const{id:t}=e,n=x(t,h);return a.jsx(s.Button,{disabled:!t,mode:"ghost",text:"Manage Translations",icon:l.CogIcon,onClick:()=>n()})}function C(e){const{apiVersion:t=y,language:n,languageField:i,documentId:o,schemaType:u,source:c,disabled:d=!1}=e,p=r.useClient({apiVersion:t}),g=s.useToast(),h=f.default.useCallback((()=>{const e=c?c._id:"draft.".concat(o),t=p.transaction();c||t.createIfNotExists({_id:e,_type:u});const a=p.patch(e).set({[i]:n.id});t.patch(a),t.commit().then((()=>{g.push({title:"Set document language to ".concat(n.title),status:"success"})})).catch((e=>(console.error(e),g.push({title:"Failed to set document language to ".concat(n.title),status:"error"}))))}),[c,o,p,i,n,u,g]);return a.jsx(s.Button,{mode:"ghost",text:n.title,icon:l.ChevronRightIcon,onClick:()=>h(),disabled:d,justify:"flex-start"})}function O(e){const{apiVersion:t=y,schemaType:n,documentId:i,languageField:u}=e,c=r.useClient({apiVersion:t}),d=Array.isArray(e.supportedLanguages)?e.supportedLanguages:j((async()=>"function"==typeof e.supportedLanguages?e.supportedLanguages(c):e.supportedLanguages),[]),[g,m]=o.useState(!1),v=o.useCallback((()=>m((e=>!e))),[]),[b,x]=o.useState(null),[T,O]=o.useState(null),I=o.useCallback((()=>m(!1)),[]);s.useClickOutside(I,[b,T]);const{data:S,loading:w,error:P}=function(e,t){const{data:n,loading:a,error:r}=p.useListeningQuery("*[_type == $translationSchema && $id in translations[].value._ref][0]",{params:{id:e,translationSchema:h}});return{data:n,loading:a,error:r}}(i),{draft:F,published:q}=r.useEditState(i,n),L=F||q,A=null==L?void 0:L[u],z=d.some((e=>e.id===A)),B=f.default.useMemo((()=>{const e=d.every((e=>e.id&&e.title));return e||console.warn('Not all languages are valid. It should be an array of objects with an "id" and "title" property. Or a function that returns an array of objects with an "id" and "title" property.',d),e}),[d]),D=a.jsx(s.Box,{overflow:"auto",children:P?a.jsx(s.Card,{tone:"critical",padding:2,children:a.jsxs(s.Text,{children:["Error: ",P]})}):a.jsxs(s.Stack,{padding:1,space:1,children:[d.length>0?a.jsxs(a.Fragment,{children:[d.map(((e,t)=>{var r;return!w&&A&&z?a.jsx(_,{index:t,language:e,languageField:u,schemaType:n,documentId:i,disabled:w||!B,current:e.id===A,metadata:S,sourceId:i,sourceLanguageId:A,translation:null==S?void 0:S.translations.find((t=>t._key===e.id))},e.id||e.title||"lang-".concat(t)):a.jsx(C,{languageField:u,source:L,documentId:i,schemaType:n,language:e,disabled:null!=(r=!B||(null==S?void 0:S.translations.filter((e=>{var t;return(null==(t=null==e?void 0:e.value)?void 0:t._ref)!==i})).some((t=>t._key===e.id))))&&r},e.id||e.title||"lang-".concat(t))})),w?null:a.jsxs(a.Fragment,{children:[B?null:a.jsx(s.Card,{tone:"caution",padding:3,children:a.jsx(s.Text,{size:1,children:"Not all language objects are valid. See the console."})}),A?null:a.jsx(s.Card,{tone:"caution",padding:3,children:a.jsxs(s.Text,{size:1,children:["Choose a language to ",a.jsx("br",{}),"apply to ",a.jsx("strong",{children:"this Document"})]})}),A&&!z?a.jsx(s.Card,{tone:"caution",padding:3,children:a.jsxs(s.Text,{size:1,children:["Change the current language value ",a.jsx("code",{children:A}),a.jsx("br",{}),"to one of the supported languages"]})}):null]})]}):null,a.jsx(k,{id:null==S?void 0:S._id})]})});return a.jsx(s.Popover,{constrainSize:!0,content:D,open:g,portal:!0,ref:O,children:a.jsx(s.Button,{text:"Translations",mode:"bleed",disabled:!L,tone:!L||!w&&A&&z?void 0:"caution",icon:l.TranslateIcon,onClick:v,ref:x,selected:g})})}const I={supportedLanguages:[],schemaTypes:[],languageField:"language",bulkPublish:!1},S=r.definePlugin((e=>{const{supportedLanguages:n,schemaTypes:l,languageField:o,bulkPublish:u}=t(t({},I),e);return{name:"@sanity/document-internationalization",form:{components:{input:e=>u&&"root"===e.id&&e.schemaType.name===h?a.jsx(s.Stack,{space:5,children:e.renderDefault(e)}):e.renderDefault(e)}},document:{unstable_languageFilter:(e,t)=>{const{schemaType:r,documentId:i}=t;return l.includes(r)?[...e,()=>((e,t)=>a.jsx(O,{supportedLanguages:n,schemaType:e,documentId:null!=t?t:"",languageField:o}))(r,i)]:e},badges:(e,t)=>{let{schemaType:a}=t;return l.includes(a)?[e=>function(e,t,n){var a,r;const i=(null==e?void 0:e.draft)||(null==e?void 0:e.published),s=null==i?void 0:i[n];if(!s)return null;const l=Array.isArray(t)?t.find((e=>e.id===s)):null;return{label:null!=(a=null==l?void 0:l.id)?a:String(s),title:null!=(r=null==l?void 0:l.title)?r:void 0,color:"primary"}}(e,n,o),...e]:e}},schema:{types:[m(l)],templates:(e,t)=>{let{schema:a}=t;if(!Array.isArray(n))return e;const r=l.map((e=>{var t,n;return{id:"".concat(e,"-parameterized"),title:"".concat(null!=(n=null==(t=null==a?void 0:a.get(e))?void 0:t.title)?n:e,": with Language"),schemaType:e,parameters:[{name:"languageId",title:"Language ID",type:"string"}],value:e=>{let{languageId:t}=e;return{[o]:t}}}})),i=l.flatMap((e=>n.map((t=>{var n,r;return{id:"".concat(e,"-").concat(t.id),title:"".concat(t.title," ").concat(null!=(r=null==(n=null==a?void 0:a.get(e))?void 0:n.title)?r:e),schemaType:e,value:{[o]:t.id}}}))));return[...e,...r,...i]}},plugins:[i.internationalizedArray({languages:n,fieldTypes:[r.defineField({name:"reference",type:"reference",to:l.map((e=>({type:e}))),options:{collapsed:!1,filter:e=>{let{parent:t,document:n}=e;if(!t)return null;const a=(Array.isArray(t)?t:[t]).find((e=>e._key));return(null==a?void 0:a._key)?n.schemaTypes?{filter:"_type in $schemaTypes && ".concat(o," == $language"),params:{schemaTypes:n.schemaTypes,language:a._key}}:{filter:"".concat(o," == $language"),params:{language:a._key}}:null}}},{strict:!1})]})]}}));exports.documentInternationalization=S;//# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/schema/translation/metadata.ts","../src/constants.ts","../src/hooks/useOpenInNewPane.tsx","../src/components/LanguageOption.tsx","../src/components/LanguageManage.tsx","../src/components/LanguagePatch.tsx","../src/components/MenuButton.tsx","../src/hooks/useLanguageMetadata.tsx","../src/components/BulkPublish/DocumentCheck.tsx","../src/components/BulkPublish/index.tsx","../src/plugin.tsx","../src/badges/index.tsx"],"sourcesContent":["import {defineType, defineField} from 'sanity'\nimport {TranslateIcon} from '@sanity/icons'\n\nimport {METADATA_SCHEMA_NAME} from '../../constants'\n\n// TODO: TS having a hard time determining the return type here. Likely a V3 type problem.\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\nexport default (schemaTypes: string[]) =>\n defineType({\n type: 'document',\n name: METADATA_SCHEMA_NAME,\n title: 'Translation metadata',\n icon: TranslateIcon,\n liveEdit: true,\n fields: [\n defineField({\n name: 'translations',\n type: 'internationalizedArrayReference',\n }),\n defineField({\n name: 'schemaTypes',\n description:\n 'Used to filter the reference fields above so all translations share the same types.',\n type: 'array',\n of: [{type: 'string'}],\n options: {list: schemaTypes},\n readOnly: ({value}) => Boolean(value),\n }),\n ],\n preview: {\n select: {\n translations: 'translations',\n documentSchemaTypes: 'schemaTypes',\n },\n prepare(selection) {\n const {translations, documentSchemaTypes} = selection\n const title =\n translations.length === 1 ? `1 Translation` : `${translations.length} Translations`\n const languageKeys = translations.length\n ? translations.map((t: {_key: string}) => t._key.toUpperCase()).join(', ')\n : ``\n const subtitle = [\n languageKeys ? `(${languageKeys})` : null,\n documentSchemaTypes?.length\n ? documentSchemaTypes.map((s: string) => s.toUpperCase()).join(`, `)\n : `No Schemas Defined`,\n ]\n .filter(Boolean)\n .join(` `)\n\n return {\n title,\n subtitle,\n }\n },\n },\n })\n","export const METADATA_SCHEMA_NAME = `translation.metadata`\n","import React from 'react'\nimport {usePaneRouter} from 'sanity/desk'\nimport {RouterContext} from 'sanity/router'\n\nexport function useOpenInNewPane(id?: string, type?: string) {\n const routerContext = React.useContext(RouterContext)\n const {routerPanesState, groupIndex} = usePaneRouter()\n\n const openInNewPane = React.useCallback(() => {\n if (!routerContext || !id || !type) {\n return\n }\n\n const panes = [...routerPanesState]\n panes.splice(groupIndex + 1, 0, [\n {\n id: id,\n params: {type},\n },\n ])\n\n const href = routerContext.resolvePathFromState({panes})\n routerContext.navigateUrl({path: href})\n }, [id, type, routerContext, routerPanesState, groupIndex])\n\n return openInNewPane\n}\n","import React, {useCallback} from 'react'\nimport {useClient} from 'sanity'\nimport {Button, Badge, Box, Flex, Text, useToast, Spinner} from '@sanity/ui'\nimport {uuid} from '@sanity/uuid'\nimport {SplitVerticalIcon, AddIcon, CheckmarkIcon} from '@sanity/icons'\n\nimport {Language, Metadata, TranslationReference} from '../types'\nimport {METADATA_SCHEMA_NAME} from '../constants'\nimport {useOpenInNewPane} from '../hooks/useOpenInNewPane'\n\ntype LanguageOptionProps = {\n language: Language\n languageField: string\n index: number\n schemaType: string\n documentId: string\n disabled: boolean\n current: boolean\n sourceId: string\n sourceLanguageId?: string\n metadata?: Metadata | null\n translation?: TranslationReference\n}\n\nfunction createReference(key: string, ref: string, type: string) {\n return {\n _key: key,\n value: {\n _type: 'reference',\n _ref: ref,\n _weak: true,\n _strengthenOnPublish: {\n type,\n },\n },\n }\n}\n\nexport default function LanguageOption(props: LanguageOptionProps) {\n const {\n index,\n language,\n languageField,\n schemaType,\n documentId,\n disabled,\n current,\n sourceId,\n sourceLanguageId,\n metadata,\n translation,\n } = props\n const client = useClient()\n const toast = useToast()\n\n const open = useOpenInNewPane(translation?.value?._ref, schemaType)\n const handleOpen = useCallback(() => open(), [open])\n\n const handleCreate = useCallback(async () => {\n const metadataExists = Boolean(metadata?._id)\n const transaction = client.transaction()\n\n // 1. Duplicate current document\n // 2. Update language\n // 3. Add to translation metadata\n const documentIds = documentId.startsWith(`drafts.`)\n ? [documentId, documentId.replace(`drafts.`, ``)]\n : [documentId, `drafts.${documentId}`]\n const latestDocument = await client.fetch(`*[_id in $ids]|order(_updatedAt desc)[0]`, {\n ids: documentIds,\n })\n const newTranslationDocument = {\n ...latestDocument,\n _id: `drafts.${uuid()}`,\n [languageField]: language.id,\n }\n\n transaction.create(newTranslationDocument)\n\n const metadataId = metadata?._id ?? uuid()\n const newTranslationReference = createReference(\n language.id,\n newTranslationDocument._id.replace(`drafts.`, ``),\n schemaType\n )\n\n // Create translation metadata document if it doesn't already exist\n if (metadataExists) {\n const path = `translations[${index - 1}]`\n const metadataPatch = client\n .patch(metadataId)\n .setIfMissing({translations: []})\n .insert(`before`, path, [newTranslationReference])\n\n transaction.patch(metadataPatch)\n } else {\n // Source language relies on a field named `language` on the document\n const sourceReference = sourceLanguageId\n ? createReference(sourceLanguageId, sourceId, schemaType)\n : null\n\n transaction.createIfNotExists({\n _id: metadataId,\n _type: METADATA_SCHEMA_NAME,\n schemaTypes: [schemaType],\n translations: [newTranslationReference, sourceReference].filter(Boolean),\n })\n }\n\n transaction\n .commit()\n .then(() => {\n // openDocumentInSidePane(metadataId, `translation.metadata`)\n return toast.push({\n status: 'success',\n title: `Created ${language.title} translation`,\n description: metadataExists\n ? `Updated Translations Metadata`\n : `Created Translations Metadata`,\n })\n })\n .catch((err) => {\n console.error(err)\n\n return toast.push({\n status: 'error',\n title: `Error creating translation`,\n description: err.message,\n })\n })\n }, [\n client,\n documentId,\n index,\n language,\n languageField,\n metadata?._id,\n schemaType,\n sourceId,\n sourceLanguageId,\n toast,\n ])\n\n return (\n <Button\n onClick={translation ? handleOpen : handleCreate}\n mode={current ? `default` : `bleed`}\n disabled={disabled || current}\n >\n <Flex gap={3} align=\"center\">\n {disabled ? (\n <Spinner />\n ) : (\n <Text size={2}>\n {/* eslint-disable-next-line no-nested-ternary */}\n {translation ? <SplitVerticalIcon /> : current ? <CheckmarkIcon /> : <AddIcon />}\n </Text>\n )}\n <Box flex={1}>\n <Text>{language.title}</Text>\n </Box>\n <Badge tone={disabled || current ? `default` : `primary`}>{language.id}</Badge>\n </Flex>\n </Button>\n )\n}\n","import React from 'react'\nimport {CogIcon} from '@sanity/icons'\nimport {Button} from '@sanity/ui'\n\nimport {useOpenInNewPane} from '../hooks/useOpenInNewPane'\nimport {METADATA_SCHEMA_NAME} from '../constants'\n\ntype LanguageManageProps = {\n id?: string\n}\n\nexport default function LanguageManage(props: LanguageManageProps) {\n const {id} = props\n const open = useOpenInNewPane(id, METADATA_SCHEMA_NAME)\n\n return (\n <Button\n disabled={!id}\n mode=\"ghost\"\n text=\"Manage Translations\"\n icon={CogIcon}\n onClick={() => open()}\n />\n )\n}\n","import React from 'react'\nimport {ChevronRightIcon} from '@sanity/icons'\nimport {Button, useToast} from '@sanity/ui'\nimport {SanityDocument, useClient} from 'sanity'\n\nimport {Language} from '../types'\n\ntype LanguagePatchProps = {\n language: Language\n languageField: string\n documentId: string\n schemaType: string\n source: SanityDocument | null\n disabled: boolean\n}\n\nexport default function LanguagePatch(props: LanguagePatchProps) {\n const {language, languageField, documentId, schemaType, source, disabled = false} = props\n const client = useClient()\n const toast = useToast()\n\n const handleClick = React.useCallback(() => {\n const currentId = source ? source._id : `draft.${documentId}`\n const transaction = client.transaction()\n\n if (!source) {\n transaction.createIfNotExists({\n _id: currentId,\n _type: schemaType,\n })\n }\n\n const patch = client.patch(currentId).set({[languageField]: language.id})\n transaction.patch(patch)\n\n transaction\n .commit()\n .then(() => {\n toast.push({\n title: `Set document language to ${language.title}`,\n status: `success`,\n })\n })\n .catch((err) => {\n console.error(err)\n\n return toast.push({\n title: `Failed to set document language to ${language.title}`,\n status: `error`,\n })\n })\n }, [source, documentId, client, languageField, language, schemaType, toast])\n\n return (\n <Button\n mode=\"ghost\"\n text={language.title}\n icon={ChevronRightIcon}\n onClick={() => handleClick()}\n disabled={disabled}\n justify=\"flex-start\"\n />\n )\n}\n","import React, {useCallback, useState} from 'react'\nimport {Text, Card, useClickOutside, Stack, Popover, Button, Box} from '@sanity/ui'\nimport {TranslateIcon} from '@sanity/icons'\nimport {useEditState} from 'sanity'\n\nimport {Language} from '../types'\nimport LanguageOption from './LanguageOption'\nimport {useTranslationMetadata} from '../hooks/useLanguageMetadata'\nimport LanguageManage from './LanguageManage'\nimport LanguagePatch from './LanguagePatch'\n\ntype MenuButtonProps = {\n supportedLanguages: Language[]\n schemaType: string\n documentId: string\n languageField: string\n}\n\nexport default function MenuButton(props: MenuButtonProps) {\n const {supportedLanguages, schemaType, documentId, languageField} = props\n\n const [open, setOpen] = useState(false)\n const handleClick = useCallback(() => setOpen((o) => !o), [])\n const [button, setButton] = useState<HTMLElement | null>(null)\n const [popover, setPopover] = useState<HTMLElement | null>(null)\n const handleClickOutside = useCallback(() => setOpen(false), [])\n useClickOutside(handleClickOutside, [button, popover])\n const {data: metadata, loading, error} = useTranslationMetadata(documentId, schemaType)\n const {draft, published} = useEditState(documentId, schemaType)\n const source = draft || published\n\n const sourceLanguageId = source?.[languageField] as string | undefined\n const sourceLanguageIsValid = supportedLanguages.some((l) => l.id === sourceLanguageId)\n\n const content = (\n <Box overflow=\"auto\">\n {error ? (\n <Card tone=\"critical\" padding={2}>\n <Text>Error: {error}</Text>\n </Card>\n ) : (\n <Stack padding={1} space={1}>\n {supportedLanguages.length > 0 ? (\n <>\n {supportedLanguages.map((language, langIndex) =>\n !loading && sourceLanguageId && sourceLanguageIsValid ? (\n // Button to duplicate this document to a new translation\n // And either create or update the metadata document\n <LanguageOption\n key={language.id}\n index={langIndex}\n language={language}\n languageField={languageField}\n schemaType={schemaType}\n documentId={documentId}\n disabled={loading}\n current={language.id === sourceLanguageId}\n metadata={metadata}\n sourceId={documentId}\n sourceLanguageId={sourceLanguageId}\n translation={metadata?.translations.find((t) => t._key === language.id)}\n />\n ) : (\n // Button to set a language field on *this* document\n <LanguagePatch\n key={language.id}\n languageField={languageField}\n source={source}\n documentId={documentId}\n schemaType={schemaType}\n language={language}\n // Only allow language patch change to:\n // - Keys not in metadata\n // - The key of this document in the metadata\n disabled={\n metadata?.translations\n .filter((t) => t?.value?._ref !== documentId)\n .some((t) => t._key === language.id) ?? false\n }\n />\n )\n )}\n {/* Once metadata is loaded, there may be issues */}\n {loading ? null : (\n <>\n {/* Current document has no language field */}\n {sourceLanguageId ? null : (\n <Card tone=\"caution\" padding={3}>\n <Text size={1}>\n Choose a language to <br />\n apply to <strong>this Document</strong>\n </Text>\n </Card>\n )}\n {/* Current document has an invalid language field */}\n {sourceLanguageId && !sourceLanguageIsValid ? (\n <Card tone=\"caution\" padding={3}>\n <Text size={1}>\n Change the current language value <code>{sourceLanguageId}</code>\n <br />\n to one of the supported languages\n </Text>\n </Card>\n ) : null}\n </>\n )}\n </>\n ) : null}\n <LanguageManage id={metadata?._id} />\n </Stack>\n )}\n </Box>\n )\n\n return (\n <Popover constrainSize content={content} open={open} portal ref={setPopover}>\n <Button\n text=\"Translations\"\n mode=\"bleed\"\n disabled={!source}\n tone={\n !source || (!loading && sourceLanguageId && sourceLanguageIsValid) ? undefined : `caution`\n }\n icon={TranslateIcon}\n onClick={handleClick}\n ref={setButton}\n selected={open}\n />\n </Popover>\n )\n}\n","import React from 'react'\nimport {useListeningQuery} from 'sanity-plugin-utils'\nimport {METADATA_SCHEMA_NAME} from '../constants'\n\nimport {Metadata} from '../types'\n\nexport function useTranslationMetadata(\n id: string,\n schemaType: string\n): {\n data: Metadata | null\n loading: boolean\n error: boolean\n} {\n const query = `*[_type == $translationSchema && $id in translations[].value._ref][0]`\n const {data, loading, error} = useListeningQuery<Metadata>(query, {\n params: {id, translationSchema: METADATA_SCHEMA_NAME},\n })\n\n return {data, loading, error}\n}\n","import React from 'react'\nimport {Card, Spinner} from '@sanity/ui'\nimport {\n useEditState,\n useValidationStatus,\n SanityPreview as Preview,\n SchemaType,\n useSchema,\n} from 'sanity'\n\ntype DocumentCheckProps = {\n id: string\n addId: (id: string) => void\n removeId: (id: string) => void\n}\n\n// Check if the document has a draft\n// Check if that draft is valid\n// Report back to parent that it can be added to bulk publish\nexport default function DocumentCheck(props: DocumentCheckProps) {\n const {id, addId, removeId} = props\n const editState = useEditState(id, ``)\n const validationStatus = useValidationStatus(id, ``)\n const schema = useSchema()\n\n const validationHasErrors = React.useMemo(() => {\n return (\n validationStatus.validation.length > 0 &&\n validationStatus.validation.find((item) => item.level === 'error')\n )\n }, [validationStatus])\n\n React.useEffect(() => {\n if (validationHasErrors) {\n addId(id)\n } else {\n removeId(id)\n }\n }, [addId, id, removeId, validationHasErrors])\n\n // We only care about drafts\n if (!editState.draft) {\n return null\n }\n\n return (\n <Card border padding={2} tone={validationHasErrors ? `critical` : `positive`}>\n {editState.published ? (\n <Preview\n layout=\"default\"\n value={editState.published}\n schemaType={schema.get(editState.published._type) as SchemaType}\n />\n ) : (\n <Spinner />\n )}\n </Card>\n )\n}\n","import React, {useCallback} from 'react'\nimport {Box, Text, Stack, Button, useToast} from '@sanity/ui'\nimport {\n InputProps,\n Reference,\n SanityDocument,\n KeyedObject,\n TypedObject,\n useClient,\n useWorkspace,\n} from 'sanity'\nimport DocumentCheck from './DocumentCheck'\n\nexport type TranslationReference = KeyedObject & TypedObject & {value: Reference}\n\nexport type TranslationMetadataDocument = SanityDocument & {\n translations: TranslationReference[]\n schemaTypes: string[]\n}\n\nexport default function BulkPublish(props: InputProps) {\n const {translations} = props.value as TranslationMetadataDocument\n const client = useClient({apiVersion: `v2022-11-21`})\n const {projectId, dataset} = useWorkspace()\n const toast = useToast()\n const [invalidIds, setInvalidIds] = React.useState<string[]>([])\n\n const addId = useCallback((id: string) => {\n setInvalidIds((ids) => [...ids, id])\n }, [])\n\n const removeId = useCallback((id: string) => {\n setInvalidIds((ids) => ids.filter((i) => i !== id))\n }, [])\n\n const handleBulkPublish = useCallback(() => {\n const body = translations.map((translation) => ({documentId: translation.value._ref}))\n client\n .request({\n uri: `/publish/${projectId}/${dataset}`,\n method: 'POST',\n body,\n })\n .then((res) => {\n toast.push({\n status: 'success',\n title: 'Success',\n description: 'Bulk publish complete',\n })\n })\n .catch((err) => {\n console.error(err)\n toast.push({\n status: 'error',\n title: 'Error',\n description: 'Bulk publish failed',\n })\n })\n }, [translations, client, projectId, dataset, toast])\n\n // TODO: Hide all this if none of the documents have drafts\n return translations?.length > 0 ? (\n <Stack space={4}>\n <Stack space={3}>\n <Text weight=\"bold\" size={1}>\n Bulk publishing\n </Text>\n <Text>\n There{' '}\n {translations.length === 1 ? `is 1 document` : `are ${translations.length} documents`}.\n </Text>\n {invalidIds.length > 0 ? (\n <Text weight=\"medium\">\n {invalidIds.length === 1 ? `1 draft has` : `${invalidIds.length} drafts have`}{' '}\n validation issues that must addressed first.\n </Text>\n ) : (\n <Text>They are all valid.</Text>\n )}\n </Stack>\n <Stack space={2}>\n {translations.map((translation) => (\n <DocumentCheck\n key={translation._key}\n id={translation.value._ref}\n addId={addId}\n removeId={removeId}\n />\n ))}\n </Stack>\n <Button\n text={`Simultaneously Publish ${\n translations.length === 1 ? `1 Document` : `${translations.length} Documents`\n }`}\n onClick={handleBulkPublish}\n disabled={Boolean(invalidIds.length)}\n />\n </Stack>\n ) : null\n}\n","import React from 'react'\nimport {definePlugin, defineField} from 'sanity'\nimport {internationalizedArray} from 'sanity-plugin-internationalized-array'\nimport {Stack} from '@sanity/ui'\n\nimport metadata from './schema/translation/metadata'\nimport MenuButton from './components/MenuButton'\nimport {PluginConfig} from './types'\nimport {LanguageBadge} from './badges'\nimport {METADATA_SCHEMA_NAME} from './constants'\nimport BulkPublish from './components/BulkPublish'\n\nconst DEFAULT_CONFIG = {\n supportedLanguages: [],\n schemaTypes: [],\n languageField: `language`,\n bulkPublish: false,\n}\n\nexport const documentInternationalization = definePlugin<PluginConfig>((config) => {\n const {supportedLanguages, schemaTypes, languageField, bulkPublish} = {\n ...DEFAULT_CONFIG,\n ...config,\n }\n\n const renderLanguageFilter = (schemaType: string, documentId?: string) => {\n return (\n <MenuButton\n supportedLanguages={supportedLanguages}\n schemaType={schemaType}\n documentId={documentId ?? ``}\n languageField={languageField}\n />\n )\n }\n\n return {\n name: '@sanity/document-internationalization',\n\n // Adds:\n // - A bulk-publishing UI component to the form\n // - Will only work for projects on a compatible plan\n form: {\n components: {\n input: (props) => {\n if (\n bulkPublish &&\n props.id === 'root' &&\n props.schemaType.name === METADATA_SCHEMA_NAME\n ) {\n return (\n <Stack space={5}>\n <BulkPublish {...props} />\n {props.renderDefault(props)}\n </Stack>\n )\n }\n\n return props.renderDefault(props)\n },\n },\n },\n\n // Adds:\n // - The `Translations` dropdown to the editing form\n // - `Badges` to documents with a language value\n document: {\n unstable_languageFilter: (prev, ctx) => {\n const {schemaType, documentId} = ctx\n\n return schemaTypes.includes(schemaType)\n ? [...prev, () => renderLanguageFilter(schemaType, documentId)]\n : prev\n },\n badges: (prev, {schemaType}) => {\n if (!schemaTypes.includes(schemaType)) {\n return prev\n }\n\n return [(props) => LanguageBadge(props, supportedLanguages, languageField), ...prev]\n },\n },\n\n // Adds:\n // - The `Translations metadata` document type to the schema\n schema: {\n // Create the metadata document type\n types: [metadata(schemaTypes)],\n\n // For every schema type this plugin is enabled on\n // Create an initial value template to set the language\n templates: (prev, {schema}) => {\n const parameterizedTemplates = schemaTypes.map((schemaType) => ({\n id: `${schemaType}-parameterized`,\n title: `${schema?.get(schemaType)?.title ?? schemaType}: with Language`,\n schemaType,\n parameters: [{name: `languageId`, title: `Language ID`, type: `string`}],\n value: ({languageId}: {languageId: string}) => ({\n [languageField]: languageId,\n }),\n }))\n\n const staticTemplates = schemaTypes.flatMap((schemaType) => {\n return supportedLanguages.map((language) => ({\n id: `${schemaType}-${language.id}`,\n title: `${language.title} Lesson`,\n schemaType,\n value: {\n [languageField]: language.id,\n },\n }))\n })\n\n return [...prev, ...parameterizedTemplates, ...staticTemplates]\n },\n },\n\n // Uses:\n // - `sanity-plugin-internationalized-array` to maintain the translations array\n plugins: [\n // Translation metadata stores its references using this plugin\n // It cuts down on attribute usage and gives UI conveniences to add new translations\n internationalizedArray({\n languages: supportedLanguages,\n fieldTypes: [\n // TODO: The plugin should allow this kind of input\n // @ts-ignore\n defineField(\n {\n name: 'reference',\n type: 'reference',\n to: schemaTypes.map((type) => ({type: type})),\n // TODO: Add a validation rule to *ensure* the document's language matches the array key\n // Reference filters don't actually enforce validation!\n // validation: (Rule) => Rule.custom(),\n options: {\n collapsed: false,\n // TODO: Update type once it knows the values of this filter\n // @ts-ignore\n filter: ({parent, document}) => {\n if (!parent) return null\n\n // I'm not sure in what instance there's an array of parents\n // But the Type suggests it's possible\n const parentArray = Array.isArray(parent) ? parent : [parent]\n const language = parentArray.find((p) => p._key)\n\n if (!language?._key) return null\n\n if (document.schemaTypes) {\n return {\n filter: `_type in $schemaTypes && ${languageField} == $language`,\n params: {schemaTypes: document.schemaTypes, language: language._key},\n }\n }\n\n return {\n filter: `${languageField} == $language`,\n params: {language: language._key},\n }\n },\n },\n },\n {strict: false}\n ),\n ],\n }),\n ],\n }\n})\n","import {DocumentBadgeDescription, DocumentBadgeProps} from 'sanity'\n\nimport {Language} from '../types'\n\nexport function LanguageBadge(\n props: DocumentBadgeProps,\n supportedLanguages: Language[],\n languageField: string\n): DocumentBadgeDescription | null {\n const source = props?.draft || props?.published\n const languageId = source?.[languageField]\n const language = supportedLanguages.find((l) => l.id === languageId)\n\n if (!language) {\n return null\n }\n\n return {\n label: language.id,\n title: language.title,\n color: `primary`,\n }\n}\n"],"names":["metadata","schemaTypes","defineType","type","name","title","icon","TranslateIcon","liveEdit","fields","defineField","description","of","options","list","readOnly","_ref","value","Boolean","preview","select","translations","documentSchemaTypes","prepare","selection","length","languageKeys","map","t","_key","toUpperCase","join","subtitle","s","filter","useOpenInNewPane","id","routerContext","React","useContext","RouterContext","routerPanesState","groupIndex","usePaneRouter","useCallback","panes","splice","params","href","resolvePathFromState","navigateUrl","path","createReference","key","ref","_type","_weak","_strengthenOnPublish","LanguageOption","props","_a","index","language","languageField","schemaType","documentId","disabled","current","sourceId","sourceLanguageId","translation","client","useClient","toast","useToast","open","handleOpen","handleCreate","async","metadataExists","_id","transaction","documentIds","startsWith","replace","concat","newTranslationDocument","fetch","ids","uuid","create","metadataId","newTranslationReference","metadataPatch","patch","setIfMissing","insert","sourceReference","createIfNotExists","commit","then","push","status","catch","err","console","error","message","jsx","Button","onClick","mode","children","jsxs","Flex","gap","align","Spinner","Text","size","SplitVerticalIcon","CheckmarkIcon","AddIcon","Box","flex","Badge","tone","LanguageManage","text","CogIcon","LanguagePatch","source","handleClick","currentId","set","ChevronRightIcon","justify","MenuButton","supportedLanguages","setOpen","useState","o","button","setButton","popover","setPopover","handleClickOutside","useClickOutside","data","loading","useListeningQuery","translationSchema","useTranslationMetadata","draft","published","useEditState","sourceLanguageIsValid","some","l","content","overflow","Card","padding","Stack","space","Fragment","langIndex","find","Popover","constrainSize","portal","selected","DocumentCheck","addId","removeId","editState","validationStatus","useValidationStatus","schema","useSchema","validationHasErrors","useMemo","validation","item","level","useEffect","border","Preview","layout","get","BulkPublish","apiVersion","projectId","dataset","useWorkspace","invalidIds","setInvalidIds","i","handleBulkPublish","body","request","uri","method","res","weight","DEFAULT_CONFIG","bulkPublish","documentInternationalization","definePlugin","config","form","components","input","renderDefault","document","unstable_languageFilter","prev","ctx","includes","renderLanguageFilter","badges","_ref2","languageId","label","color","LanguageBadge","types","templates","_ref3","_b","parameters","_ref4","flatMap","plugins","internationalizedArray","languages","fieldTypes","to","collapsed","_ref5","parent","Array","isArray","p","strict"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -1,17 +1,20 @@
1
1
  import {Plugin as Plugin_2} from 'sanity'
2
+ import type {SanityClient} from 'sanity'
2
3
 
3
4
  export declare const documentInternationalization: Plugin_2<PluginConfig>
4
5
 
5
6
  declare type Language = {
6
- id: string
7
+ id: Intl.UnicodeBCP47LocaleIdentifier
7
8
  title: string
8
9
  }
9
10
 
10
11
  declare type PluginConfig = {
11
- supportedLanguages: Language[]
12
+ supportedLanguages: SupportedLanguages
12
13
  schemaTypes: string[]
13
14
  languageField?: string
14
15
  bulkPublish?: boolean
15
16
  }
16
17
 
18
+ declare type SupportedLanguages = Language[] | ((client: SanityClient) => Promise<Language[]>)
19
+
17
20
  export {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/document-internationalization",
3
- "version": "2.0.0-studio-v3-plugin-v2.2",
3
+ "version": "2.0.0-studio-v3-plugin-v2.4",
4
4
  "description": "Create unique translations of a document based on its language, joined by a shared reference document.",
5
5
  "keywords": [
6
6
  "sanity",
@@ -49,10 +49,10 @@
49
49
  "dependencies": {
50
50
  "@sanity/icons": "^1.3.6",
51
51
  "@sanity/incompatible-plugin": "^1.0.4",
52
- "@sanity/ui": "1.0.0-beta.32",
52
+ "@sanity/ui": "^1.0.0",
53
53
  "@sanity/uuid": "^3.0.1",
54
- "sanity-plugin-internationalized-array": "^1.4.1",
55
- "sanity-plugin-utils": "^1.0.0"
54
+ "sanity-plugin-internationalized-array": "^1.5.0",
55
+ "sanity-plugin-utils": "^1.0.1"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@commitlint/cli": "^17.2.0",
@@ -74,12 +74,12 @@
74
74
  "prettier-plugin-packagejson": "^2.3.0",
75
75
  "react": "^18",
76
76
  "rimraf": "^3.0.2",
77
- "sanity": "3.0.0-rc.2",
77
+ "sanity": "^3.0.0",
78
78
  "typescript": "^4.9.3"
79
79
  },
80
80
  "peerDependencies": {
81
81
  "react": "^18",
82
- "sanity": "dev-preview || 3.0.0-rc.2"
82
+ "sanity": "^3.0.0"
83
83
  },
84
84
  "engines": {
85
85
  "node": ">=14"
@@ -1,23 +1,27 @@
1
1
  import {DocumentBadgeDescription, DocumentBadgeProps} from 'sanity'
2
2
 
3
- import {Language} from '../types'
3
+ import {SupportedLanguages} from '../types'
4
4
 
5
5
  export function LanguageBadge(
6
6
  props: DocumentBadgeProps,
7
- supportedLanguages: Language[],
7
+ supportedLanguages: SupportedLanguages,
8
8
  languageField: string
9
9
  ): DocumentBadgeDescription | null {
10
10
  const source = props?.draft || props?.published
11
11
  const languageId = source?.[languageField]
12
- const language = supportedLanguages.find((l) => l.id === languageId)
13
12
 
14
- if (!language) {
13
+ if (!languageId) {
15
14
  return null
16
15
  }
17
16
 
17
+ const language = Array.isArray(supportedLanguages)
18
+ ? supportedLanguages.find((l) => l.id === languageId)
19
+ : null
20
+
21
+ // Currently we only show the language id if the supportedLanguages are async
18
22
  return {
19
- label: language.id,
20
- title: language.title,
23
+ label: language?.id ?? String(languageId),
24
+ title: language?.title ?? undefined,
21
25
  color: `primary`,
22
26
  }
23
27
  }
@@ -1,12 +1,6 @@
1
1
  import React from 'react'
2
2
  import {Card, Spinner} from '@sanity/ui'
3
- import {
4
- useEditState,
5
- useValidationStatus,
6
- SanityPreview as Preview,
7
- SchemaType,
8
- useSchema,
9
- } from 'sanity'
3
+ import {useEditState, useValidationStatus, Preview, SchemaType, useSchema} from 'sanity'
10
4
 
11
5
  type DocumentCheckProps = {
12
6
  id: string
@@ -10,17 +10,19 @@ import {
10
10
  useWorkspace,
11
11
  } from 'sanity'
12
12
  import DocumentCheck from './DocumentCheck'
13
+ import {API_VERSION} from '../../constants'
13
14
 
14
15
  export type TranslationReference = KeyedObject & TypedObject & {value: Reference}
15
16
 
16
17
  export type TranslationMetadataDocument = SanityDocument & {
17
18
  translations: TranslationReference[]
18
19
  schemaTypes: string[]
20
+ apiVersion?: string
19
21
  }
20
22
 
21
23
  export default function BulkPublish(props: InputProps) {
22
- const {translations} = props.value as TranslationMetadataDocument
23
- const client = useClient({apiVersion: `v2022-11-21`})
24
+ const {apiVersion = API_VERSION, translations} = props.value as TranslationMetadataDocument
25
+ const client = useClient({apiVersion})
24
26
  const {projectId, dataset} = useWorkspace()
25
27
  const toast = useToast()
26
28
  const [invalidIds, setInvalidIds] = React.useState<string[]>([])
@@ -5,7 +5,7 @@ import {uuid} from '@sanity/uuid'
5
5
  import {SplitVerticalIcon, AddIcon, CheckmarkIcon} from '@sanity/icons'
6
6
 
7
7
  import {Language, Metadata, TranslationReference} from '../types'
8
- import {METADATA_SCHEMA_NAME} from '../constants'
8
+ import {API_VERSION, METADATA_SCHEMA_NAME} from '../constants'
9
9
  import {useOpenInNewPane} from '../hooks/useOpenInNewPane'
10
10
 
11
11
  type LanguageOptionProps = {
@@ -20,6 +20,7 @@ type LanguageOptionProps = {
20
20
  sourceLanguageId?: string
21
21
  metadata?: Metadata | null
22
22
  translation?: TranslationReference
23
+ apiVersion?: string
23
24
  }
24
25
 
25
26
  function createReference(key: string, ref: string, type: string) {
@@ -38,6 +39,7 @@ function createReference(key: string, ref: string, type: string) {
38
39
 
39
40
  export default function LanguageOption(props: LanguageOptionProps) {
40
41
  const {
42
+ apiVersion = API_VERSION,
41
43
  index,
42
44
  language,
43
45
  languageField,
@@ -50,7 +52,7 @@ export default function LanguageOption(props: LanguageOptionProps) {
50
52
  metadata,
51
53
  translation,
52
54
  } = props
53
- const client = useClient()
55
+ const client = useClient({apiVersion})
54
56
  const toast = useToast()
55
57
 
56
58
  const open = useOpenInNewPane(translation?.value?._ref, schemaType)
@@ -4,6 +4,7 @@ import {Button, useToast} from '@sanity/ui'
4
4
  import {SanityDocument, useClient} from 'sanity'
5
5
 
6
6
  import {Language} from '../types'
7
+ import {API_VERSION} from '../constants'
7
8
 
8
9
  type LanguagePatchProps = {
9
10
  language: Language
@@ -12,11 +13,20 @@ type LanguagePatchProps = {
12
13
  schemaType: string
13
14
  source: SanityDocument | null
14
15
  disabled: boolean
16
+ apiVersion?: string
15
17
  }
16
18
 
17
19
  export default function LanguagePatch(props: LanguagePatchProps) {
18
- const {language, languageField, documentId, schemaType, source, disabled = false} = props
19
- const client = useClient()
20
+ const {
21
+ apiVersion = API_VERSION,
22
+ language,
23
+ languageField,
24
+ documentId,
25
+ schemaType,
26
+ source,
27
+ disabled = false,
28
+ } = props
29
+ const client = useClient({apiVersion})
20
30
  const toast = useToast()
21
31
 
22
32
  const handleClick = React.useCallback(() => {
@@ -1,23 +1,37 @@
1
+ import {suspend} from 'suspend-react'
1
2
  import React, {useCallback, useState} from 'react'
2
3
  import {Text, Card, useClickOutside, Stack, Popover, Button, Box} from '@sanity/ui'
3
4
  import {TranslateIcon} from '@sanity/icons'
4
- import {useEditState} from 'sanity'
5
+ import {useClient, useEditState, useWorkspace} from 'sanity'
5
6
 
6
- import {Language} from '../types'
7
+ import {SupportedLanguages} from '../types'
7
8
  import LanguageOption from './LanguageOption'
8
9
  import {useTranslationMetadata} from '../hooks/useLanguageMetadata'
9
10
  import LanguageManage from './LanguageManage'
10
11
  import LanguagePatch from './LanguagePatch'
12
+ import {API_VERSION} from '../constants'
11
13
 
12
14
  type MenuButtonProps = {
13
- supportedLanguages: Language[]
15
+ supportedLanguages: SupportedLanguages
14
16
  schemaType: string
15
17
  documentId: string
16
18
  languageField: string
19
+ apiVersion?: string
17
20
  }
18
21
 
19
22
  export default function MenuButton(props: MenuButtonProps) {
20
- const {supportedLanguages, schemaType, documentId, languageField} = props
23
+ const {apiVersion = API_VERSION, schemaType, documentId, languageField} = props
24
+
25
+ const client = useClient({apiVersion})
26
+ const supportedLanguages = Array.isArray(props.supportedLanguages)
27
+ ? props.supportedLanguages
28
+ : // eslint-disable-next-line require-await
29
+ suspend(async () => {
30
+ if (typeof props.supportedLanguages === 'function') {
31
+ return props.supportedLanguages(client)
32
+ }
33
+ return props.supportedLanguages
34
+ }, [])
21
35
 
22
36
  const [open, setOpen] = useState(false)
23
37
  const handleClick = useCallback(() => setOpen((o) => !o), [])
@@ -31,6 +45,17 @@ export default function MenuButton(props: MenuButtonProps) {
31
45
 
32
46
  const sourceLanguageId = source?.[languageField] as string | undefined
33
47
  const sourceLanguageIsValid = supportedLanguages.some((l) => l.id === sourceLanguageId)
48
+ const allLanguagesAreValid = React.useMemo(() => {
49
+ const valid = supportedLanguages.every((l) => l.id && l.title)
50
+ if (!valid) {
51
+ console.warn(
52
+ `Not all languages are valid. It should be an array of objects with an "id" and "title" property. Or a function that returns an array of objects with an "id" and "title" property.`,
53
+ supportedLanguages
54
+ )
55
+ }
56
+
57
+ return valid
58
+ }, [supportedLanguages])
34
59
 
35
60
  const content = (
36
61
  <Box overflow="auto">
@@ -47,13 +72,13 @@ export default function MenuButton(props: MenuButtonProps) {
47
72
  // Button to duplicate this document to a new translation
48
73
  // And either create or update the metadata document
49
74
  <LanguageOption
50
- key={language.id}
75
+ key={language.id || language.title || `lang-${langIndex}`}
51
76
  index={langIndex}
52
77
  language={language}
53
78
  languageField={languageField}
54
79
  schemaType={schemaType}
55
80
  documentId={documentId}
56
- disabled={loading}
81
+ disabled={loading || !allLanguagesAreValid}
57
82
  current={language.id === sourceLanguageId}
58
83
  metadata={metadata}
59
84
  sourceId={documentId}
@@ -63,7 +88,7 @@ export default function MenuButton(props: MenuButtonProps) {
63
88
  ) : (
64
89
  // Button to set a language field on *this* document
65
90
  <LanguagePatch
66
- key={language.id}
91
+ key={language.id || language.title || `lang-${langIndex}`}
67
92
  languageField={languageField}
68
93
  source={source}
69
94
  documentId={documentId}
@@ -73,9 +98,11 @@ export default function MenuButton(props: MenuButtonProps) {
73
98
  // - Keys not in metadata
74
99
  // - The key of this document in the metadata
75
100
  disabled={
76
- metadata?.translations
77
- .filter((t) => t?.value?._ref !== documentId)
78
- .some((t) => t._key === language.id) ?? false
101
+ (!allLanguagesAreValid ||
102
+ metadata?.translations
103
+ .filter((t) => t?.value?._ref !== documentId)
104
+ .some((t) => t._key === language.id)) ??
105
+ false
79
106
  }
80
107
  />
81
108
  )
@@ -83,6 +110,12 @@ export default function MenuButton(props: MenuButtonProps) {
83
110
  {/* Once metadata is loaded, there may be issues */}
84
111
  {loading ? null : (
85
112
  <>
113
+ {/* Not all languages are valid */}
114
+ {allLanguagesAreValid ? null : (
115
+ <Card tone="caution" padding={3}>
116
+ <Text size={1}>Not all language objects are valid. See the console.</Text>
117
+ </Card>
118
+ )}
86
119
  {/* Current document has no language field */}
87
120
  {sourceLanguageId ? null : (
88
121
  <Card tone="caution" padding={3}>
package/src/constants.ts CHANGED
@@ -1 +1,2 @@
1
1
  export const METADATA_SCHEMA_NAME = `translation.metadata`
2
+ export const API_VERSION = `2022-11-27`
package/src/plugin.tsx CHANGED
@@ -50,7 +50,7 @@ export const documentInternationalization = definePlugin<PluginConfig>((config)
50
50
  ) {
51
51
  return (
52
52
  <Stack space={5}>
53
- <BulkPublish {...props} />
53
+ {/* <BulkPublish {...props} /> */}
54
54
  {props.renderDefault(props)}
55
55
  </Stack>
56
56
  )
@@ -90,6 +90,11 @@ export const documentInternationalization = definePlugin<PluginConfig>((config)
90
90
  // For every schema type this plugin is enabled on
91
91
  // Create an initial value template to set the language
92
92
  templates: (prev, {schema}) => {
93
+ // Templates are not setup for async languages
94
+ if (!Array.isArray(supportedLanguages)) {
95
+ return prev
96
+ }
97
+
93
98
  const parameterizedTemplates = schemaTypes.map((schemaType) => ({
94
99
  id: `${schemaType}-parameterized`,
95
100
  title: `${schema?.get(schemaType)?.title ?? schemaType}: with Language`,
@@ -103,7 +108,7 @@ export const documentInternationalization = definePlugin<PluginConfig>((config)
103
108
  const staticTemplates = schemaTypes.flatMap((schemaType) => {
104
109
  return supportedLanguages.map((language) => ({
105
110
  id: `${schemaType}-${language.id}`,
106
- title: `${language.title} Lesson`,
111
+ title: `${language.title} ${schema?.get(schemaType)?.title ?? schemaType}`,
107
112
  schemaType,
108
113
  value: {
109
114
  [languageField]: language.id,
package/src/types.ts CHANGED
@@ -1,12 +1,14 @@
1
- import {SanityDocumentLike} from 'sanity'
1
+ import type {SanityDocumentLike, SanityClient} from 'sanity'
2
2
 
3
3
  export type Language = {
4
- id: string
4
+ id: Intl.UnicodeBCP47LocaleIdentifier
5
5
  title: string
6
6
  }
7
7
 
8
+ export type SupportedLanguages = Language[] | ((client: SanityClient) => Promise<Language[]>)
9
+
8
10
  export type PluginConfig = {
9
- supportedLanguages: Language[]
11
+ supportedLanguages: SupportedLanguages
10
12
  schemaTypes: string[]
11
13
  languageField?: string
12
14
  bulkPublish?: boolean