sanity-plugin-google-translate
4.0.124.0.13
dist/index.js.map~
dist/index.js.mapModified+1−1
Index: package/dist/index.js.map
===================================================================
--- package/dist/index.js.map
+++ package/dist/index.js.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"index.js","names":["InputProps","ObjectMember","getLanguageFromMember","member","kind","key","split","pop","elementProps","id","htmlDecode","input","doc","DOMParser","parseFromString","documentElement","textContent","Box","Button","Text","Flex","Stack","useToast","Tooltip","useCallback","useState","MemberField","MemberFieldSet","MemberFieldError","set","unset","FieldMember","InputProps","ObjectInputProps","extractLanguageFromCode","getLanguageFromMember","htmlDecode","FieldNameLangPair","GoogleTranslateSchemaOptions","TranslationConfig","collectLanguageFields","members","allLanguageFields","cur","kind","language","name","push","fieldName","fieldLang","memberCur","fieldSet","GoogleTranslateInput","props","$","_c","renderDefault","onChange","value","t0","schemaType","options","apiKey","isTranslating","setIsTranslating","toast","t1","config","content","title","status","baseLanguage","filter","code","url","URL","searchParams","target","source","length","description","toLocaleUpperCase","translations","map","item","fetch","toString","then","_temp","res_0","res","error","message","data","forEach","t2","translatedText","decoded","catch","_temp2","Promise","all","handleTranslation","member","baseMember","find","_temp3","baseFieldValue","field","baseContent","isBaseLanguage","toUpperCase","renderInput","t3","renderField","renderItem","renderPreview","t4","member_0","key","item_0","err","console","json","definePlugin","GoogleTranslateInput","GoogleTranslateSchemaOptions","googleTranslate","name","form","components","input","props","options","schemaType","translate","jsonType","Error","renderDefault"],"sources":["../src/helpers/extractLanguageFromCode.ts","../src/helpers/getLanguageFromMember.ts","../src/helpers/htmlDecode.ts","../src/GoogleTranslateInput.tsx","../src/googleTranslate.tsx"],"sourcesContent":["export function extractLanguageFromCode(code = ``): string {\n if (code.length <= 2) {\n return code.toLowerCase()\n }\n\n const [languageCode] = code.split(/[-_]/)\n return (languageCode ?? code).toLowerCase()\n}\n","import {type InputProps, type ObjectMember} from 'sanity'\n\nexport function getLanguageFromMember(member: InputProps | ObjectMember): string {\n // Member is undefined\n if (!member) {\n return ``\n }\n\n // Member is an object field member\n if ('kind' in member && member.kind === 'field') {\n return member.key.split(`-`).pop() ?? ``\n } else if ('kind' in member) {\n return ``\n }\n\n // Member is an inputProps\n return member?.elementProps?.id.split(`.`).pop() ?? ``\n}\n","export function htmlDecode(input: string): string {\n const doc = new DOMParser().parseFromString(input, 'text/html')\n return doc.documentElement.textContent ?? ``\n}\n","import {Box, Button, Text, Flex, Stack} from '@sanity/ui'\nimport {useToast} from '@sanity/ui/toast'\nimport {Tooltip} from '@sanity/ui/tooltip'\nimport {useCallback, useState} from 'react'\nimport {MemberField, MemberFieldSet, MemberFieldError, set, unset} from 'sanity'\nimport type {FieldMember, InputProps, ObjectInputProps} from 'sanity'\n\nimport {extractLanguageFromCode} from './helpers/extractLanguageFromCode'\nimport {getLanguageFromMember} from './helpers/getLanguageFromMember'\nimport {htmlDecode} from './helpers/htmlDecode'\nimport type {FieldNameLangPair, GoogleTranslateSchemaOptions, TranslationConfig} from './types'\n\nfunction collectLanguageFields(members: ObjectInputProps['members']): FieldNameLangPair[] {\n const allLanguageFields: FieldNameLangPair[] = []\n\n for (const cur of members) {\n if (cur.kind === 'field') {\n const language = getLanguageFromMember(cur)\n if (language && cur.name) {\n allLanguageFields.push({\n fieldName: cur.name,\n fieldLang: language,\n })\n }\n } else if (cur.kind === 'fieldSet') {\n for (const memberCur of cur.fieldSet.members) {\n if (memberCur.kind === 'field') {\n allLanguageFields.push({\n fieldName: memberCur.name,\n fieldLang: getLanguageFromMember(memberCur),\n })\n }\n }\n }\n }\n\n return allLanguageFields\n}\n\nexport function GoogleTranslateInput(props: ObjectInputProps) {\n const {renderDefault, members, onChange, value} = props\n // oxlint-disable-next-line no-unsafe-type-assertion - plugin-specific object options\n const {apiKey} = (props.schemaType.options ?? {}) as GoogleTranslateSchemaOptions\n\n const [isTranslating, setIsTranslating] = useState(false)\n const toast = useToast()\n\n const handleTranslation = useCallback(\n (config: TranslationConfig) => {\n if (!config?.content) {\n return toast.push({\n title: `No content to translate`,\n status: `warning`,\n })\n }\n\n // Get all unique language field names and codes\n // Maybe this should be recursive, but the recommendation is only to nest 1 level deep\n // TODO: Remove hidden/filtered-out fields as this currently will write to all fields\n let allLanguageFields = collectLanguageFields(members)\n\n // If this isn't a \"translate all\" operation, just target the passed-in language\n if (config.language !== config.baseLanguage) {\n allLanguageFields = allLanguageFields.filter((code) => code.fieldName === config.language)\n }\n\n setIsTranslating(true)\n\n const url = new URL(`https://translation.googleapis.com/language/translate/v2`)\n url.searchParams.set(`key`, apiKey ?? ``)\n url.searchParams.set(`q`, config.content)\n\n // Language code might be a country/language pair like en_US\n const target = extractLanguageFromCode(config.language)\n const source = extractLanguageFromCode(config.baseLanguage)\n url.searchParams.set(`source`, source)\n\n if (allLanguageFields.length === 1 && target === source) {\n return toast.push({\n title: `Bad language pair`,\n status: `warning`,\n description: `Cannot translate from \"${source.toLocaleUpperCase()}\" to \"${target.toLocaleUpperCase()}\"`,\n })\n }\n\n const translations = allLanguageFields.map(async (item) => {\n url.searchParams.set(`target`, item.fieldLang)\n\n if (item.fieldLang === source) {\n return null\n }\n\n return fetch(url.toString())\n .then((res) => res.json())\n .then((res) => {\n if (res.error) {\n toast.push({\n title: `Error`,\n status: `error`,\n description: res.error.message,\n })\n return undefined\n }\n\n toast.push({\n title: `Translation Complete`,\n status: `success`,\n description: `Translated from \"${source.toLocaleUpperCase()}\" to \"${item.fieldLang.toLocaleUpperCase()}\"`,\n })\n\n const {data} = res\n\n if (data?.translations?.length) {\n data.translations.forEach(({translatedText}: {translatedText: string}) => {\n // Convert html entities returned in translation to a string\n const decoded = htmlDecode(translatedText)\n\n // Write translation into the correct language field\n onChange(decoded ? set(decoded, [item.fieldName]) : unset([item.fieldName]))\n })\n }\n\n return undefined\n })\n .catch((err) => {\n console.error(err)\n })\n })\n\n return Promise.all(translations).then(() => setIsTranslating(false))\n },\n [apiKey, members, onChange, toast],\n )\n\n const renderInput = useCallback(\n (member: InputProps) => {\n if (!value) {\n return renderDefault(member)\n }\n\n const language = getLanguageFromMember(member)\n const baseMember = members.find((item): item is FieldMember => item.kind === 'field')\n const baseLanguage = baseMember ? getLanguageFromMember(baseMember) : ``\n const baseFieldValue = baseMember?.field.value\n const baseContent = typeof baseFieldValue === 'string' ? baseFieldValue : ``\n const isBaseLanguage = language === baseLanguage\n\n if (!language) {\n return renderDefault(member)\n }\n\n return (\n <Flex gap={1}>\n <Box flex={1}>{renderDefault(member)}</Box>\n <Tooltip\n content={\n <Box padding={2}>\n {isBaseLanguage ? (\n <Text size={1}>\n Translate all fields from the \"{baseLanguage.toLocaleUpperCase()}\" content\n </Text>\n ) : (\n <Text size={1}>\n Translate the \"{baseLanguage.toLocaleUpperCase()}\" field content to \"\n {language.toLocaleUpperCase()}\"\n </Text>\n )}\n </Box>\n }\n fallbackPlacements={['right', 'left']}\n placement=\"top\"\n portal\n >\n <Button\n mode=\"ghost\"\n disabled={isTranslating || (isBaseLanguage && !member?.value)}\n value={language}\n text={isBaseLanguage ? `Translate All` : `Translate ${language.toUpperCase()}`}\n onClick={() =>\n handleTranslation({\n language,\n baseLanguage,\n content: baseContent,\n })\n }\n />\n </Tooltip>\n </Flex>\n )\n },\n [handleTranslation, isTranslating, members, renderDefault, value],\n )\n\n return (\n <Stack gap={4}>\n {props.members.map((member) => {\n switch (member.kind) {\n case 'field':\n return (\n <MemberField\n key={member.key}\n member={member}\n // @ts-expect-error - MemberField renderInput typings do not match custom callback\n renderInput={renderInput}\n renderPreview={props.renderPreview}\n renderField={props.renderField}\n renderItem={props.renderItem}\n />\n )\n case 'fieldSet':\n return (\n <MemberFieldSet\n key={member.key}\n member={member}\n // @ts-expect-error - MemberFieldSet renderInput typings do not match custom callback\n renderInput={renderInput}\n renderPreview={props.renderPreview}\n renderField={props.renderField}\n renderItem={props.renderItem}\n />\n )\n case 'error':\n return <MemberFieldError key={member.key} member={member} />\n default:\n return null\n }\n })}\n </Stack>\n )\n}\n","import {definePlugin} from 'sanity'\n\nimport {GoogleTranslateInput} from './GoogleTranslateInput'\nimport type {GoogleTranslateSchemaOptions} from './types'\n\nexport const googleTranslate = definePlugin(() => {\n return {\n name: 'sanity-plugin-google-translate',\n form: {\n components: {\n input: (props) => {\n // oxlint-disable-next-line no-unsafe-type-assertion - plugin-specific object options\n const options = props.schemaType.options as GoogleTranslateSchemaOptions | undefined\n\n if (options?.translate) {\n if (props.schemaType.jsonType !== 'object') {\n throw new Error(\n `The translate option is only supported on object type fields, but got ${props.schemaType.jsonType}`,\n )\n }\n\n // @ts-expect-error - form input props are wider than ObjectInputProps\n return <GoogleTranslateInput {...props} />\n }\n\n return props.renderDefault(props)\n },\n },\n },\n }\n})\n"],"mappings":";;;;;;;;AAAA,SAAgB,wBAAwB,OAAO,IAAY;CACzD,IAAI,KAAK,UAAU,GACjB,OAAO,KAAK,YAAY;CAG1B,IAAM,CAAC,gBAAgB,KAAK,MAAM,MAAM;CACxC,QAAQ,gBAAgB,KAAA,CAAM,YAAY;AAC5C;ACLA,SAAgBE,sBAAsBC,QAA2C;CAc/E,OAZKA,SAKD,UAAUA,UAAUA,OAAOC,SAAS,UAC/BD,OAAOE,IAAIC,MAAM,GAAG,CAAC,CAACC,IAAI,KAAK,KAC7B,UAAUJ,SACZ,KAIFA,QAAQK,cAAcC,GAAGH,MAAM,GAAG,CAAC,CAACC,IAAI,KAAK,KAX3C;AAYX;ACjBA,SAAgBG,WAAWC,OAAuB;CAEhD,OADY,IAAIE,UAAU,CAAC,CAACC,gBAAgBH,OAAO,WAC5CC,CAAG,CAACG,gBAAgBC,eAAe;AAC5C;ACSA,SAASwB,sBAAsBC,SAA2D;CACxF,IAAMC,oBAAyC,CAAA;CAE/C,KAAK,IAAMC,OAAOF,SAChB,IAAIE,IAAIC,SAAS,SAAS;EACxB,IAAMC,WAAWV,sBAAsBQ,GAAG;EAC1C,AAAIE,YAAYF,IAAIG,QAClBJ,kBAAkBK,KAAK;GACrBC,WAAWL,IAAIG;GACfG,WAAWJ;EACb,CAAC;CAEL,OAAO,IAAIF,IAAIC,SAAS,YACjB,KAAA,IAAMM,aAAaP,IAAIQ,SAASV,SACnC,AAAIS,UAAUN,SAAS,WACrBF,kBAAkBK,KAAK;EACrBC,WAAWE,UAAUJ;EACrBG,WAAWd,sBAAsBe,SAAS;CAC5C,CAAC;CAMT,OAAOR;AACT;AAEA,SAAOU,qBAAAC,OAAA;CAAA,IAAAC,IAAAC,EAAA,EAAA,GACL,EAAAC,eAAAf,SAAAgB,UAAAC,UAAkDL,OAAKM;CAAA,AAAAL,EAAA,OAAAD,MAAAO,WAAAC,UAEPF,KAAAL,EAAA,MAA9BK,KAAAN,MAAKO,WAAWC,WAAhB,CAA6B,GAACP,EAAA,KAAAD,MAAAO,WAAAC,SAAAP,EAAA,KAAAK;CAAhD,IAAA,EAAAG,WAAkBH,IAElB,CAAAI,eAAAC,oBAA0CvC,SAAS,EAAK,GACxDwC,QAAc3C,SAAS,GAAC4C;CAAA,AAAAZ,EAAA,OAAAQ,UAAAR,EAAA,OAAAb,WAAAa,EAAA,OAAAG,YAAAH,EAAA,OAAAW,SAGtBC,MAAAC,WAAA;EACE,IAAI,CAACA,QAAMC,SAAS,OACXH,MAAKlB,KAAM;GAAAsB,OACT;GAAyBC,QACxB;EACV,CAAC;EAMH,IAAA5B,oBAAwBF,sBAAsBC,OAAO;EAOrDuB,AAJIG,OAAMtB,aAAcsB,OAAMI,iBAC5B7B,oBAAoBA,kBAAiB8B,QAAQC,SAAUA,KAAIzB,cAAemB,OAAMtB,QAAS,IAG3FmB,iBAAiB,EAAI;EAErB,IAAAU,MAAY,IAAIC,IAAI,0DAA0D;EAE9ED,AADAA,IAAGE,aAAa/C,IAAK,OAAOiC,UAAA,EAAY,GACxCY,IAAGE,aAAa/C,IAAK,KAAKsC,OAAMC,OAAQ;EAGxC,IAAAS,SAAe3C,wBAAwBiC,OAAMtB,QAAS,GACtDiC,SAAe5C,wBAAwBiC,OAAMI,YAAa;EAG1D,IAFAG,IAAGE,aAAa/C,IAAK,UAAUiD,MAAM,GAEjCpC,kBAAiBqC,WAAY,KAAKF,WAAWC,QAAM,OAC9Cb,MAAKlB,KAAM;GAAAsB,OACT;GAAmBC,QAClB;GAASU,aACJ,0BAA0BF,OAAMG,kBAAmB,EAAC,QAASJ,OAAMI,kBAAmB,EAAC;EACtG,CAAC;EAGH,IAAAC,eAAqBxC,kBAAiByC,IAAK,OAAAC,UACzCV,IAAGE,aAAa/C,IAAK,UAAUuD,KAAInC,SAAU,GAEzCmC,KAAInC,cAAe6B,SACd,OAGFO,MAAMX,IAAGY,SAAU,CAAC,CAAC,CAAAC,KACpBC,KAAmB,CAAC,CAAAD,MACpBE,UAAA;GACJ,IAAIC,MAAGC,OAAM;IACX1B,MAAKlB,KAAM;KAAAsB,OACF;KAAOC,QACN;KAAOU,aACFU,MAAGC,MAAMC;IACxB,CAAC;IAAC;GAAA;GAIJ3B,MAAKlB,KAAM;IAAAsB,OACF;IAAsBC,QACrB;IAASU,aACJ,oBAAoBF,OAAMG,kBAAmB,EAAC,QAASG,KAAInC,UAAUgC,kBAAmB,EAAC;GACxG,CAAC;GAED,IAAA,EAAAY,SAAeH;GAEf,AAAIG,MAAIX,cAAsBH,UAC5Bc,KAAIX,aAAaY,SAASC,OAAA;IAAC,IAAA,EAAAC,mBAAAD,IAEzBE,UAAgB7D,WAAW4D,cAAc;IAGzCvC,SAASwC,UAAUpE,IAAIoE,SAAS,CAACb,KAAIpC,SAAU,CAA2B,IAAtBlB,MAAM,CAACsD,KAAIpC,SAAU,CAAC,CAAC;GAAC,CAC7E;EACF,CAGF,CAAC,CAAAkD,MACKC,MAEN,EACJ;EAAC,OAEKC,QAAOC,IAAKnB,YAAY,CAAC,CAAAK,WAAYvB,iBAAiB,EAAK,CAAC;CAAC,GACrEV,EAAA,KAAAQ,QAAAR,EAAA,KAAAb,SAAAa,EAAA,KAAAG,UAAAH,EAAA,KAAAW,OAAAX,EAAA,KAAAY,MAAAA,KAAAZ,EAAA;CAnFH,IAAAgD,oBAA0BpC,IAqFzB6B;CAAA,AAAAzC,EAAA,OAAAgD,qBAAAhD,EAAA,OAAAS,iBAAAT,EAAA,OAAAb,WAAAa,EAAA,QAAAE,iBAAAF,EAAA,QAAAI,SAGCqC,MAAAQ,WAAA;EACE,IAAI,CAAC7C,OAAK,OACDF,cAAc+C,MAAM;EAG7B,IAAA1D,WAAiBV,sBAAsBoE,MAAM,GAC7CC,aAAmB/D,QAAOgE,KAAMC,MAAoD,GACpFnC,eAAqBiC,aAAarE,sBAAsBqE,UAAe,IAAlD,IACrBG,iBAAuBH,YAAUI,MAAalD,OAC9CmD,cAAoB,OAAOF,kBAAmB,WAA1BA,iBAAA,IACpBG,iBAAuBjE,aAAa0B;EAInC,OAFI1B,WAKH,qBAAC,MAAD;GAAW,KAAA;GAAX,UAAA,CACE,oBAAC,KAAD;IAAW,MAAA;IAAIW,UAAAA,cAAc+C,MAAM;GAA/B,CAAA,GACJ,oBAAC,SAAD;IAEI,SAAA,oBAAC,KAAD;KAAc,SAAA;KACXO,UAAAA,iBACC,qBAAC,MAAD;MAAY,MAAA;MAAZ,UAAA;OAAe;OACmBvC,aAAYU,kBAAmB;OAAE;MAD9D;KAIL,CAAA,IAAA,qBAAC,MAAD;MAAY,MAAA;MAAZ,UAAA;OAAe;OACGV,aAAYU,kBAAmB;OAAE;OAChDpC,SAAQoC,kBAAmB;OAAE;MAF3B;;IANL,CAAA;IAac,oBAAA,CAAC,SAAS,MAAM;IAC1B,WAAA;IACV,QAAA;IAEA,UAAA,oBAAC,QAAD;KACO,MAAA;KACK,UAAAlB,iBAAkB+C,kBAAA,CAAmBP,QAAM7C;KAC9Cb,OAAAA;KACD,MAAAiE,iBAAA,kBAAA,aAAgDjE,SAAQkE,YAAa;KAClE,eACPT,kBAAkB;MAAAzD;MAAA0B;MAAAH,SAGPyC;KACX,CAAC;IAAC,CAAA;GA7BA,CAAA,CAFL;OAJErD,cAAc+C,MAAM;CAuCpB,GAEVjD,EAAA,KAAAgD,mBAAAhD,EAAA,KAAAS,eAAAT,EAAA,KAAAb,SAAAa,EAAA,MAAAE,eAAAF,EAAA,MAAAI,OAAAJ,EAAA,MAAAyC,MAAAA,KAAAzC,EAAA;CAvDH,IAAA0D,cAAoBjB,IAyDnBkB;CAAA,IAAA3D,EAAA,QAAAD,MAAAZ,WAAAa,EAAA,QAAAD,MAAA6D,eAAA5D,EAAA,QAAAD,MAAA8D,cAAA7D,EAAA,QAAAD,MAAA+D,iBAAA9D,EAAA,QAAA0D,aAAA;EAAA,IAAAK;EAmCK/D,AAnCLA,EAAA,QAAAD,MAAA6D,eAAA5D,EAAA,QAAAD,MAAA8D,cAAA7D,EAAA,QAAAD,MAAA+D,iBAAA9D,EAAA,QAAA0D,eAIsBK,MAAAC,aAAA;GACjB,QAAQf,SAAM3D,MAAd;IAAmB,KACZ,SAAO,OAER,oBAAC,aAAD;KAEU2D,QAAAA;KAEKS;KACE,eAAA3D,MAAK+D;KACP,aAAA/D,MAAK6D;KACN,YAAA7D,MAAK8D;IAAW,GANvBZ,SAAMgB,GAMiB;IAC5B,KAED,YAAU,OAEX,oBAAC,gBAAD;KAEUhB,QAAAA;KAEKS;KACE,eAAA3D,MAAK+D;KACP,aAAA/D,MAAK6D;KACN,YAAA7D,MAAK8D;IAAW,GANvBZ,SAAMgB,GAMiB;IAC5B,KAED,SAAO,OACH,oBAAC,kBAAD,EAA2ChB,QAAAA,SAAM,GAA1BA,SAAMgB,GAAoB;IAAI,SAAA,OAErD;GACX;EAAC,GACFjE,EAAA,MAAAD,MAAA6D,aAAA5D,EAAA,MAAAD,MAAA8D,YAAA7D,EAAA,MAAAD,MAAA+D,eAAA9D,EAAA,MAAA0D,aAAA1D,EAAA,MAAA+D,MAAAA,KAAA/D,EAAA,KA/BA2D,KAAA5D,MAAKZ,QAAQ0C,IAAKkC,EA+BlB,GAAC/D,EAAA,MAAAD,MAAAZ,SAAAa,EAAA,MAAAD,MAAA6D,aAAA5D,EAAA,MAAAD,MAAA8D,YAAA7D,EAAA,MAAAD,MAAA+D,eAAA9D,EAAA,MAAA0D,aAAA1D,EAAA,MAAA2D;CAAA,OAAAA,KAAA3D,EAAA;CAAA,IAAA+D;CACI,OADJ/D,EAAA,QAAA2D,KACII,KAAA/D,EAAA,OAjCR+D,KAAA,oBAAC,OAAD;EAAY,KAAA;EACTJ,UAAAA;CADG,CAAA,GAiCE3D,EAAA,MAAA2D,IAAA3D,EAAA,MAAA+D,KAjCRA;AAiCQ;AA5LL,SAAAX,OAAAc,QAAA;CAAA,OAsG8DpC,OAAIxC,SAAU;AAAO;AAtGnF,SAAAuD,OAAAsB,KAAA;CAsFKC,QAAO/B,MAAO8B,GAAG;AAAC;AAtFvB,SAAAjC,MAAAE,KAAA;CAAA,OAsDkBA,IAAGiC,KAAM;AAAC;ACxFnC,MAAaI,kBAAkBH,oBACtB;CACLI,MAAM;CACNC,MAAM,EACJC,YAAY,EACVC,QAAQC,UAAU;EAIhB,IAFgBA,MAAME,WAAWD,SAEpBE,WAAW;GACtB,IAAIH,MAAME,WAAWE,aAAa,UAChC,MAAUC,MACR,yEAAyEL,MAAME,WAAWE,UAC5F;GAIF,OAAO,oBAAC,sBAAD,EAAsB,GAAIJ,MAAM,CAAA;EACzC;EAEA,OAAOA,MAAMM,cAAcN,KAAK;CAClC,EACF,EACF;AACF,EACD"}
\ No newline at end of file
+{"version":3,"file":"index.js","names":["props.schemaType.options ?? {}","options","(config: TranslationConfig) => {\n if (!config?.content) {\n return toast.push({\n title: `No content to translate`,\n status: `warning`,\n })\n }\n\n // Get all unique language field names and codes\n // Maybe this should be recursive, but the recommendation is only to nest 1 level deep\n // TODO: Remove hidden/filtered-out fields as this currently will write to all fields\n let allLanguageFields = collectLanguageFields(members)\n\n // If this isn't a \"translate all\" operation, just target the passed-in language\n if (config.language !== config.baseLanguage) {\n allLanguageFields = allLanguageFields.filter((code) => code.fieldName === config.language)\n }\n\n setIsTranslating(true)\n\n const url = new URL(`https://translation.googleapis.com/language/translate/v2`)\n url.searchParams.set(`key`, apiKey ?? ``)\n url.searchParams.set(`q`, config.content)\n\n // Language code might be a country/language pair like en_US\n const target = extractLanguageFromCode(config.language)\n const source = extractLanguageFromCode(config.baseLanguage)\n url.searchParams.set(`source`, source)\n\n if (allLanguageFields.length === 1 && target === source) {\n return toast.push({\n title: `Bad language pair`,\n status: `warning`,\n description: `Cannot translate from \"${source.toLocaleUpperCase()}\" to \"${target.toLocaleUpperCase()}\"`,\n })\n }\n\n const translations = allLanguageFields.map(async (item) => {\n url.searchParams.set(`target`, item.fieldLang)\n\n if (item.fieldLang === source) {\n return null\n }\n\n return fetch(url.toString())\n .then((res) => res.json())\n .then((res) => {\n if (res.error) {\n toast.push({\n title: `Error`,\n status: `error`,\n description: res.error.message,\n })\n return undefined\n }\n\n toast.push({\n title: `Translation Complete`,\n status: `success`,\n description: `Translated from \"${source.toLocaleUpperCase()}\" to \"${item.fieldLang.toLocaleUpperCase()}\"`,\n })\n\n const {data} = res\n\n if (data?.translations?.length) {\n data.translations.forEach(({translatedText}: {translatedText: string}) => {\n // Convert html entities returned in translation to a string\n const decoded = htmlDecode(translatedText)\n\n // Write translation into the correct language field\n onChange(decoded ? set(decoded, [item.fieldName]) : unset([item.fieldName]))\n })\n }\n\n return undefined\n })\n .catch((err) => {\n console.error(err)\n })\n })\n\n return Promise.all(translations).then(() => setIsTranslating(false))\n }","(res) => res.json()","res","{translatedText}: {translatedText: string}","(err) => {\n console.error(err)\n }","useCallback(\n (config: TranslationConfig) => {\n if (!config?.content) {\n return toast.push({\n title: `No content to translate`,\n status: `warning`,\n })\n }\n\n // Get all unique language field names and codes\n // Maybe this should be recursive, but the recommendation is only to nest 1 level deep\n // TODO: Remove hidden/filtered-out fields as this currently will write to all fields\n let allLanguageFields = collectLanguageFields(members)\n\n // If this isn't a \"translate all\" operation, just target the passed-in language\n if (config.language !== config.baseLanguage) {\n allLanguageFields = allLanguageFields.filter((code) => code.fieldName === config.language)\n }\n\n setIsTranslating(true)\n\n const url = new URL(`https://translation.googleapis.com/language/translate/v2`)\n url.searchParams.set(`key`, apiKey ?? ``)\n url.searchParams.set(`q`, config.content)\n\n // Language code might be a country/language pair like en_US\n const target = extractLanguageFromCode(config.language)\n const source = extractLanguageFromCode(config.baseLanguage)\n url.searchParams.set(`source`, source)\n\n if (allLanguageFields.length === 1 && target === source) {\n return toast.push({\n title: `Bad language pair`,\n status: `warning`,\n description: `Cannot translate from \"${source.toLocaleUpperCase()}\" to \"${target.toLocaleUpperCase()}\"`,\n })\n }\n\n const translations = allLanguageFields.map(async (item) => {\n url.searchParams.set(`target`, item.fieldLang)\n\n if (item.fieldLang === source) {\n return null\n }\n\n return fetch(url.toString())\n .then((res) => res.json())\n .then((res) => {\n if (res.error) {\n toast.push({\n title: `Error`,\n status: `error`,\n description: res.error.message,\n })\n return undefined\n }\n\n toast.push({\n title: `Translation Complete`,\n status: `success`,\n description: `Translated from \"${source.toLocaleUpperCase()}\" to \"${item.fieldLang.toLocaleUpperCase()}\"`,\n })\n\n const {data} = res\n\n if (data?.translations?.length) {\n data.translations.forEach(({translatedText}: {translatedText: string}) => {\n // Convert html entities returned in translation to a string\n const decoded = htmlDecode(translatedText)\n\n // Write translation into the correct language field\n onChange(decoded ? set(decoded, [item.fieldName]) : unset([item.fieldName]))\n })\n }\n\n return undefined\n })\n .catch((err) => {\n console.error(err)\n })\n })\n\n return Promise.all(translations).then(() => setIsTranslating(false))\n },\n [apiKey, members, onChange, toast],\n )","(member: InputProps) => {\n if (!value) {\n return renderDefault(member)\n }\n\n const language = getLanguageFromMember(member)\n const baseMember = members.find((item): item is FieldMember => item.kind === 'field')\n const baseLanguage = baseMember ? getLanguageFromMember(baseMember) : ``\n const baseFieldValue = baseMember?.field.value\n const baseContent = typeof baseFieldValue === 'string' ? baseFieldValue : ``\n const isBaseLanguage = language === baseLanguage\n\n if (!language) {\n return renderDefault(member)\n }\n\n return (\n <Flex gap={1}>\n <Box flex={1}>{renderDefault(member)}</Box>\n <Tooltip\n content={\n <Box padding={2}>\n {isBaseLanguage ? (\n <Text size={1}>\n Translate all fields from the \"{baseLanguage.toLocaleUpperCase()}\" content\n </Text>\n ) : (\n <Text size={1}>\n Translate the \"{baseLanguage.toLocaleUpperCase()}\" field content to \"\n {language.toLocaleUpperCase()}\"\n </Text>\n )}\n </Box>\n }\n fallbackPlacements={['right', 'left']}\n placement=\"top\"\n portal\n >\n <Button\n mode=\"ghost\"\n disabled={isTranslating || (isBaseLanguage && !member?.value)}\n value={language}\n text={isBaseLanguage ? `Translate All` : `Translate ${language.toUpperCase()}`}\n onClick={() =>\n handleTranslation({\n language,\n baseLanguage,\n content: baseContent,\n })\n }\n />\n </Tooltip>\n </Flex>\n )\n }","(item): item is FieldMember => item.kind === 'field'","useCallback(\n (member: InputProps) => {\n if (!value) {\n return renderDefault(member)\n }\n\n const language = getLanguageFromMember(member)\n const baseMember = members.find((item): item is FieldMember => item.kind === 'field')\n const baseLanguage = baseMember ? getLanguageFromMember(baseMember) : ``\n const baseFieldValue = baseMember?.field.value\n const baseContent = typeof baseFieldValue === 'string' ? baseFieldValue : ``\n const isBaseLanguage = language === baseLanguage\n\n if (!language) {\n return renderDefault(member)\n }\n\n return (\n <Flex gap={1}>\n <Box flex={1}>{renderDefault(member)}</Box>\n <Tooltip\n content={\n <Box padding={2}>\n {isBaseLanguage ? (\n <Text size={1}>\n Translate all fields from the \"{baseLanguage.toLocaleUpperCase()}\" content\n </Text>\n ) : (\n <Text size={1}>\n Translate the \"{baseLanguage.toLocaleUpperCase()}\" field content to \"\n {language.toLocaleUpperCase()}\"\n </Text>\n )}\n </Box>\n }\n fallbackPlacements={['right', 'left']}\n placement=\"top\"\n portal\n >\n <Button\n mode=\"ghost\"\n disabled={isTranslating || (isBaseLanguage && !member?.value)}\n value={language}\n text={isBaseLanguage ? `Translate All` : `Translate ${language.toUpperCase()}`}\n onClick={() =>\n handleTranslation({\n language,\n baseLanguage,\n content: baseContent,\n })\n }\n />\n </Tooltip>\n </Flex>\n )\n },\n [handleTranslation, isTranslating, members, renderDefault, value],\n )","props.members.map((member) => {\n switch (member.kind) {\n case 'field':\n return (\n <MemberField\n key={member.key}\n member={member}\n // @ts-expect-error - MemberField renderInput typings do not match custom callback\n renderInput={renderInput}\n renderPreview={props.renderPreview}\n renderField={props.renderField}\n renderItem={props.renderItem}\n />\n )\n case 'fieldSet':\n return (\n <MemberFieldSet\n key={member.key}\n member={member}\n // @ts-expect-error - MemberFieldSet renderInput typings do not match custom callback\n renderInput={renderInput}\n renderPreview={props.renderPreview}\n renderField={props.renderField}\n renderItem={props.renderItem}\n />\n )\n case 'error':\n return <MemberFieldError key={member.key} member={member} />\n default:\n return null\n }\n })","members","renderField","renderItem","renderPreview","(member) => {\n switch (member.kind) {\n case 'field':\n return (\n <MemberField\n key={member.key}\n member={member}\n // @ts-expect-error - MemberField renderInput typings do not match custom callback\n renderInput={renderInput}\n renderPreview={props.renderPreview}\n renderField={props.renderField}\n renderItem={props.renderItem}\n />\n )\n case 'fieldSet':\n return (\n <MemberFieldSet\n key={member.key}\n member={member}\n // @ts-expect-error - MemberFieldSet renderInput typings do not match custom callback\n renderInput={renderInput}\n renderPreview={props.renderPreview}\n renderField={props.renderField}\n renderItem={props.renderItem}\n />\n )\n case 'error':\n return <MemberFieldError key={member.key} member={member} />\n default:\n return null\n }\n }","member","<Stack gap={4}>\n {props.members.map((member) => {\n switch (member.kind) {\n case 'field':\n return (\n <MemberField\n key={member.key}\n member={member}\n // @ts-expect-error - MemberField renderInput typings do not match custom callback\n renderInput={renderInput}\n renderPreview={props.renderPreview}\n renderField={props.renderField}\n renderItem={props.renderItem}\n />\n )\n case 'fieldSet':\n return (\n <MemberFieldSet\n key={member.key}\n member={member}\n // @ts-expect-error - MemberFieldSet renderInput typings do not match custom callback\n renderInput={renderInput}\n renderPreview={props.renderPreview}\n renderField={props.renderField}\n renderItem={props.renderItem}\n />\n )\n case 'error':\n return <MemberFieldError key={member.key} member={member} />\n default:\n return null\n }\n })}\n </Stack>","item"],"sources":["../src/helpers/extractLanguageFromCode.ts","../src/helpers/getLanguageFromMember.ts","../src/helpers/htmlDecode.ts","../src/GoogleTranslateInput.tsx","../src/googleTranslate.tsx"],"sourcesContent":["export function extractLanguageFromCode(code = ``): string {\n if (code.length <= 2) {\n return code.toLowerCase()\n }\n\n const [languageCode] = code.split(/[-_]/)\n return (languageCode ?? code).toLowerCase()\n}\n","import {type InputProps, type ObjectMember} from 'sanity'\n\nexport function getLanguageFromMember(member: InputProps | ObjectMember): string {\n // Member is undefined\n if (!member) {\n return ``\n }\n\n // Member is an object field member\n if ('kind' in member && member.kind === 'field') {\n return member.key.split(`-`).pop() ?? ``\n } else if ('kind' in member) {\n return ``\n }\n\n // Member is an inputProps\n return member?.elementProps?.id.split(`.`).pop() ?? ``\n}\n","export function htmlDecode(input: string): string {\n const doc = new DOMParser().parseFromString(input, 'text/html')\n return doc.documentElement.textContent ?? ``\n}\n","import {Box, Button, Text, Flex, Stack} from '@sanity/ui'\nimport {useToast} from '@sanity/ui/toast'\nimport {Tooltip} from '@sanity/ui/tooltip'\nimport {useCallback, useState} from 'react'\nimport {MemberField, MemberFieldSet, MemberFieldError, set, unset} from 'sanity'\nimport type {FieldMember, InputProps, ObjectInputProps} from 'sanity'\n\nimport {extractLanguageFromCode} from './helpers/extractLanguageFromCode'\nimport {getLanguageFromMember} from './helpers/getLanguageFromMember'\nimport {htmlDecode} from './helpers/htmlDecode'\nimport type {FieldNameLangPair, GoogleTranslateSchemaOptions, TranslationConfig} from './types'\n\nfunction collectLanguageFields(members: ObjectInputProps['members']): FieldNameLangPair[] {\n const allLanguageFields: FieldNameLangPair[] = []\n\n for (const cur of members) {\n if (cur.kind === 'field') {\n const language = getLanguageFromMember(cur)\n if (language && cur.name) {\n allLanguageFields.push({\n fieldName: cur.name,\n fieldLang: language,\n })\n }\n } else if (cur.kind === 'fieldSet') {\n for (const memberCur of cur.fieldSet.members) {\n if (memberCur.kind === 'field') {\n allLanguageFields.push({\n fieldName: memberCur.name,\n fieldLang: getLanguageFromMember(memberCur),\n })\n }\n }\n }\n }\n\n return allLanguageFields\n}\n\nexport function GoogleTranslateInput(props: ObjectInputProps) {\n const {renderDefault, members, onChange, value} = props\n // oxlint-disable-next-line no-unsafe-type-assertion - plugin-specific object options\n const {apiKey} = (props.schemaType.options ?? {}) as GoogleTranslateSchemaOptions\n\n const [isTranslating, setIsTranslating] = useState(false)\n const toast = useToast()\n\n const handleTranslation = useCallback(\n (config: TranslationConfig) => {\n if (!config?.content) {\n return toast.push({\n title: `No content to translate`,\n status: `warning`,\n })\n }\n\n // Get all unique language field names and codes\n // Maybe this should be recursive, but the recommendation is only to nest 1 level deep\n // TODO: Remove hidden/filtered-out fields as this currently will write to all fields\n let allLanguageFields = collectLanguageFields(members)\n\n // If this isn't a \"translate all\" operation, just target the passed-in language\n if (config.language !== config.baseLanguage) {\n allLanguageFields = allLanguageFields.filter((code) => code.fieldName === config.language)\n }\n\n setIsTranslating(true)\n\n const url = new URL(`https://translation.googleapis.com/language/translate/v2`)\n url.searchParams.set(`key`, apiKey ?? ``)\n url.searchParams.set(`q`, config.content)\n\n // Language code might be a country/language pair like en_US\n const target = extractLanguageFromCode(config.language)\n const source = extractLanguageFromCode(config.baseLanguage)\n url.searchParams.set(`source`, source)\n\n if (allLanguageFields.length === 1 && target === source) {\n return toast.push({\n title: `Bad language pair`,\n status: `warning`,\n description: `Cannot translate from \"${source.toLocaleUpperCase()}\" to \"${target.toLocaleUpperCase()}\"`,\n })\n }\n\n const translations = allLanguageFields.map(async (item) => {\n url.searchParams.set(`target`, item.fieldLang)\n\n if (item.fieldLang === source) {\n return null\n }\n\n return fetch(url.toString())\n .then((res) => res.json())\n .then((res) => {\n if (res.error) {\n toast.push({\n title: `Error`,\n status: `error`,\n description: res.error.message,\n })\n return undefined\n }\n\n toast.push({\n title: `Translation Complete`,\n status: `success`,\n description: `Translated from \"${source.toLocaleUpperCase()}\" to \"${item.fieldLang.toLocaleUpperCase()}\"`,\n })\n\n const {data} = res\n\n if (data?.translations?.length) {\n data.translations.forEach(({translatedText}: {translatedText: string}) => {\n // Convert html entities returned in translation to a string\n const decoded = htmlDecode(translatedText)\n\n // Write translation into the correct language field\n onChange(decoded ? set(decoded, [item.fieldName]) : unset([item.fieldName]))\n })\n }\n\n return undefined\n })\n .catch((err) => {\n console.error(err)\n })\n })\n\n return Promise.all(translations).then(() => setIsTranslating(false))\n },\n [apiKey, members, onChange, toast],\n )\n\n const renderInput = useCallback(\n (member: InputProps) => {\n if (!value) {\n return renderDefault(member)\n }\n\n const language = getLanguageFromMember(member)\n const baseMember = members.find((item): item is FieldMember => item.kind === 'field')\n const baseLanguage = baseMember ? getLanguageFromMember(baseMember) : ``\n const baseFieldValue = baseMember?.field.value\n const baseContent = typeof baseFieldValue === 'string' ? baseFieldValue : ``\n const isBaseLanguage = language === baseLanguage\n\n if (!language) {\n return renderDefault(member)\n }\n\n return (\n <Flex gap={1}>\n <Box flex={1}>{renderDefault(member)}</Box>\n <Tooltip\n content={\n <Box padding={2}>\n {isBaseLanguage ? (\n <Text size={1}>\n Translate all fields from the \"{baseLanguage.toLocaleUpperCase()}\" content\n </Text>\n ) : (\n <Text size={1}>\n Translate the \"{baseLanguage.toLocaleUpperCase()}\" field content to \"\n {language.toLocaleUpperCase()}\"\n </Text>\n )}\n </Box>\n }\n fallbackPlacements={['right', 'left']}\n placement=\"top\"\n portal\n >\n <Button\n mode=\"ghost\"\n disabled={isTranslating || (isBaseLanguage && !member?.value)}\n value={language}\n text={isBaseLanguage ? `Translate All` : `Translate ${language.toUpperCase()}`}\n onClick={() =>\n handleTranslation({\n language,\n baseLanguage,\n content: baseContent,\n })\n }\n />\n </Tooltip>\n </Flex>\n )\n },\n [handleTranslation, isTranslating, members, renderDefault, value],\n )\n\n return (\n <Stack gap={4}>\n {props.members.map((member) => {\n switch (member.kind) {\n case 'field':\n return (\n <MemberField\n key={member.key}\n member={member}\n // @ts-expect-error - MemberField renderInput typings do not match custom callback\n renderInput={renderInput}\n renderPreview={props.renderPreview}\n renderField={props.renderField}\n renderItem={props.renderItem}\n />\n )\n case 'fieldSet':\n return (\n <MemberFieldSet\n key={member.key}\n member={member}\n // @ts-expect-error - MemberFieldSet renderInput typings do not match custom callback\n renderInput={renderInput}\n renderPreview={props.renderPreview}\n renderField={props.renderField}\n renderItem={props.renderItem}\n />\n )\n case 'error':\n return <MemberFieldError key={member.key} member={member} />\n default:\n return null\n }\n })}\n </Stack>\n )\n}\n","import {definePlugin} from 'sanity'\n\nimport {GoogleTranslateInput} from './GoogleTranslateInput'\nimport type {GoogleTranslateSchemaOptions} from './types'\n\nexport const googleTranslate = definePlugin(() => {\n return {\n name: 'sanity-plugin-google-translate',\n form: {\n components: {\n input: (props) => {\n // oxlint-disable-next-line no-unsafe-type-assertion - plugin-specific object options\n const options = props.schemaType.options as GoogleTranslateSchemaOptions | undefined\n\n if (options?.translate) {\n if (props.schemaType.jsonType !== 'object') {\n throw new Error(\n `The translate option is only supported on object type fields, but got ${props.schemaType.jsonType}`,\n )\n }\n\n // @ts-expect-error - form input props are wider than ObjectInputProps\n return <GoogleTranslateInput {...props} />\n }\n\n return props.renderDefault(props)\n },\n },\n },\n }\n})\n"],"mappings":"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"}
\ No newline at end of file