sanity-plugin-google-translate

4.0.134.0.14
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":["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
+{"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","_c"],"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