gt-sanity 4.0.11 β†’ 4.0.13

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/utils/shared.ts","../src/adapter/core.ts","../src/utils/localeDisplay.ts","../src/hooks/useClient.ts","../src/hooks/useSecrets.ts","../src/components/shared/BaseTranslationWrapper.tsx","../src/serialization/BaseDocumentMerger.ts","../src/utils/documentIds.ts","../src/configuration/utils/findLatestDraft.ts","../src/configuration/utils/findDocumentAtRevision.ts","../src/configuration/utils/requireSourceDocument.ts","../src/utils/applyDocuments.ts","../src/utils/randomKey.ts","../src/utils/translationMetadata.ts","../src/configuration/baseDocumentLevelConfig/helpers/createI18nDocAndPatchMetadata.ts","../src/configuration/baseDocumentLevelConfig/helpers/getOrCreateTranslationMetadata.ts","../src/configuration/baseDocumentLevelConfig/helpers/patchI18nDoc.ts","../src/configuration/baseDocumentLevelConfig/documentLevelPatch.ts","../src/serialization/internationalizedArray/detect.ts","../src/serialization/internationalizedArray/merge.ts","../src/configuration/internationalizedArrayConfig/internationalizedArrayPatch.ts","../src/serialization/deserialize/helpers.ts","../src/serialization/data.ts","../src/serialization/BaseSerializationConfig.ts","../src/serialization/helpers.ts","../src/serialization/deserialize/BaseDocumentDeserializer.ts","../src/serialization/serialize/fieldFilters.ts","../src/serialization/serialize/index.ts","../src/serialization/internationalizedArray/collapse.ts","../src/utils/serialize.ts","../src/translation/strategy.ts","../src/translation/uploadFiles.ts","../src/translation/initProject.ts","../src/translation/createJobs.ts","../src/translation/collectExistingTranslations.ts","../src/translation/captureExistingTranslations.ts","../src/translation/uploadTranslations.ts","../src/translation/downloadTranslations.ts","../src/translation/checkTranslationStatus.ts","../src/translation/importDocument.ts","../src/sanity-api/resolveRefs.ts","../src/sanity-api/findDocuments.ts","../src/utils/batchProcessor.ts","../src/utils/importUtils.ts","../src/sanity-api/publishDocuments.ts","../src/adapter/getLocales.ts","../src/utils/translationPreferences.ts","../src/components/TranslationsProvider.tsx","../src/components/page/SaveLocalTranslationsDialog.tsx","../src/utils/debugInfo.ts","../src/utils/translationSummary.ts","../src/components/page/DebugInfoDialog.tsx","../src/components/shared/LocaleLabel.tsx","../src/components/shared/LanguageStatus.tsx","../src/utils/languageStatusState.ts","../src/components/shared/LocaleCheckbox.tsx","../src/components/tab/TranslationView.tsx","../src/actions/translateAction.tsx","../src/schema/fieldLevelConfig.ts","../src/components/page/TranslationsTable.tsx","../src/components/page/TranslateAllDialog.tsx","../src/components/page/ImportAllDialog.tsx","../src/components/page/ImportMissingDialog.tsx","../src/components/page/UploadExistingDialog.tsx","../src/components/page/BatchProgress.tsx","../src/components/page/TranslationsTool.tsx","../src/utils/locales.ts","../src/structure/localizedStructure.ts","../src/components/tab/TranslationsTab.tsx","../src/index.ts"],"sourcesContent":["export const SECRETS_NAMESPACE = 'generaltranslation.secrets';\n\n/**\n * Sanity API version used by every client and structure builder this plugin\n * creates. Sanity requires a pinned version on document lists that supply a\n * custom filter, and warns when one is omitted.\n */\nexport const SANITY_API_VERSION = '2025-09-15';\n","import { GT } from 'generaltranslation';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport type { Secrets } from '../types';\nimport type {\n TranslateDocumentFilter,\n DedupeFields,\n IgnoreFields,\n SkipFields,\n FieldLevelTranslationMode,\n TranslationPreferences,\n} from './types';\nimport { SECRETS_NAMESPACE } from '../utils/shared';\nimport type { PortableTextHtmlComponents } from '@portabletext/to-html';\nimport type { CustomDeserializers } from '../serialization/types';\nexport const gt = new GT();\n\n/**\n * Built-in defaults for the automatic actions.\n *\n * The line is whether an action can put content in front of readers, or write\n * to something already in front of them:\n * - `autoRefresh` only polls for status, and auto-import depends on it.\n * - `autoImport` writes drafts, which are cheap to discard.\n * - `autoPatchReferences` normally writes a draft too, but rewrites references\n * on an already-published translation when that document has no draft, so it\n * is opt-in.\n * - `autoPublish` publishes, which no switch can undo.\n */\nexport const DEFAULT_TRANSLATION_PREFERENCES: TranslationPreferences = {\n autoRefresh: true,\n autoImport: true,\n autoPatchReferences: false,\n autoPublish: false,\n // Opt-in: turning this on means Sanity overwrites whatever General\n // Translation holds for that source version, including a completed\n // translation that has not been imported yet.\n preserveExistingTranslations: false,\n};\n\nexport function overrideConfig(secrets: Secrets | null) {\n gt.setConfig({\n ...(secrets?.project && { projectId: secrets?.project }),\n ...(secrets?.secret && { apiKey: secrets?.secret }),\n });\n}\n\nexport class GTConfig {\n secretsNamespace: string;\n languageField: string;\n sourceLocale: string;\n locales: string[];\n singletons: string[];\n singletonMapping: (sourceDocumentId: string, locale: string) => string;\n ignoreFields: IgnoreFields[];\n dedupeFields: DedupeFields[];\n skipFields: SkipFields[];\n translateDocuments: TranslateDocumentFilter[];\n additionalStopTypes: string[];\n additionalSerializers: Partial<PortableTextHtmlComponents>;\n additionalDeserializers: CustomDeserializers;\n additionalBlockDeserializers: unknown[];\n translationLevel: FieldLevelTranslationMode;\n fieldLevelDocuments: TranslateDocumentFilter[];\n preferences: TranslationPreferences;\n\n private static instance: GTConfig;\n constructor(\n secretsNamespace: string,\n languageField: string,\n sourceLocale: string,\n locales: string[],\n singletons: string[],\n singletonMapping: (sourceDocumentId: string, locale: string) => string,\n ignoreFields: IgnoreFields[],\n dedupeFields: DedupeFields[],\n skipFields: SkipFields[],\n translateDocuments: TranslateDocumentFilter[],\n additionalStopTypes: string[] = [],\n additionalSerializers: Partial<PortableTextHtmlComponents> = {},\n additionalDeserializers: CustomDeserializers = { types: {} },\n additionalBlockDeserializers: unknown[] = [],\n translationLevel: FieldLevelTranslationMode = 'document',\n fieldLevelDocuments: TranslateDocumentFilter[] = [],\n preferences: TranslationPreferences = DEFAULT_TRANSLATION_PREFERENCES\n ) {\n this.secretsNamespace = secretsNamespace;\n this.languageField = languageField;\n this.sourceLocale = sourceLocale;\n this.locales = locales;\n this.singletons = singletons;\n this.singletonMapping = singletonMapping;\n this.ignoreFields = ignoreFields;\n this.dedupeFields = dedupeFields;\n this.skipFields = skipFields;\n this.translateDocuments = translateDocuments;\n this.additionalStopTypes = additionalStopTypes;\n this.additionalSerializers = additionalSerializers;\n this.additionalDeserializers = additionalDeserializers;\n this.additionalBlockDeserializers = additionalBlockDeserializers;\n this.translationLevel = translationLevel;\n this.fieldLevelDocuments = fieldLevelDocuments;\n this.preferences = preferences;\n }\n\n static getInstance() {\n if (!this.instance) {\n this.instance = new GTConfig(\n SECRETS_NAMESPACE,\n 'language',\n gt.sourceLocale || libraryDefaultLocale,\n [],\n [],\n () => '',\n [],\n [],\n [],\n [],\n [],\n { types: {} },\n {},\n []\n );\n }\n return this.instance;\n }\n\n init(\n secretsNamespace: string,\n languageField: string,\n sourceLocale: string,\n locales: string[],\n singletons: string[],\n singletonMapping: (sourceDocumentId: string, locale: string) => string,\n ignoreFields: IgnoreFields[],\n dedupeFields: DedupeFields[],\n skipFields: SkipFields[],\n translateDocuments: TranslateDocumentFilter[],\n additionalStopTypes: string[] = [],\n additionalSerializers: Partial<PortableTextHtmlComponents> = {},\n additionalDeserializers: CustomDeserializers = { types: {} },\n additionalBlockDeserializers: unknown[] = [],\n translationLevel: FieldLevelTranslationMode = 'document',\n fieldLevelDocuments: TranslateDocumentFilter[] = [],\n preferences: TranslationPreferences = DEFAULT_TRANSLATION_PREFERENCES\n ) {\n this.secretsNamespace = secretsNamespace;\n this.languageField = languageField;\n this.sourceLocale = sourceLocale;\n this.locales = locales;\n this.singletons = singletons;\n this.singletonMapping = singletonMapping;\n this.ignoreFields = ignoreFields;\n this.dedupeFields = dedupeFields;\n this.skipFields = skipFields;\n this.translateDocuments = translateDocuments;\n this.additionalStopTypes = additionalStopTypes;\n this.additionalSerializers = additionalSerializers;\n this.additionalDeserializers = additionalDeserializers;\n this.additionalBlockDeserializers = additionalBlockDeserializers;\n this.translationLevel = translationLevel;\n this.fieldLevelDocuments = fieldLevelDocuments;\n this.preferences = preferences;\n }\n\n getSecretsNamespace() {\n return this.secretsNamespace;\n }\n\n getLanguageField() {\n return this.languageField;\n }\n\n getSourceLocale() {\n return this.sourceLocale;\n }\n getLocales() {\n return this.locales;\n }\n getSingletons() {\n return this.singletons;\n }\n getSingletonMapping() {\n return this.singletonMapping;\n }\n getIgnoreFields() {\n return this.ignoreFields;\n }\n getDedupeFields() {\n return this.dedupeFields;\n }\n getSkipFields() {\n return this.skipFields;\n }\n getTranslateDocuments() {\n return this.translateDocuments;\n }\n getAdditionalStopTypes() {\n return this.additionalStopTypes;\n }\n getAdditionalSerializers() {\n return this.additionalSerializers;\n }\n getAdditionalDeserializers() {\n return this.additionalDeserializers;\n }\n getAdditionalBlockDeserializers() {\n return this.additionalBlockDeserializers;\n }\n getTranslationLevel() {\n return this.translationLevel;\n }\n getFieldLevelDocuments() {\n return this.fieldLevelDocuments;\n }\n getPreferences() {\n return this.preferences;\n }\n}\nexport const pluginConfig = GTConfig.getInstance();\n","import type { CustomMapping, LocaleProperties } from 'generaltranslation/types';\nimport { gt } from '../adapter/core';\n\ntype CustomMappingEntry = CustomMapping[string];\n\nexport type LocaleDisplay = {\n /** The locale code as configured, e.g. `en-US`. */\n code: string;\n /** Plain language name, e.g. `English` (never `American English`). */\n name: string;\n /** Flag emoji for the locale's region, e.g. πŸ‡ΊπŸ‡Έ. */\n emoji: string;\n /**\n * True when a string custom mapping fully defines the label: `name` is the\n * user's exact text and nothing (flag, code) should be added around it.\n */\n verbatim: boolean;\n};\n\nfunction capitalize(value: string): string {\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nexport function localeDisplayFromProperties(\n code: string,\n properties: LocaleProperties,\n mapping?: CustomMappingEntry\n): LocaleDisplay {\n // A string custom mapping replaces the entire label, flag included.\n // (The object form overrides individual properties instead, so it still\n // composes with the flag/code formatting.)\n if (typeof mapping === 'string') {\n return { code, name: mapping, emoji: '', verbatim: true };\n }\n return {\n code,\n name: capitalize(properties.languageName || properties.name || code),\n emoji: properties.emoji || '',\n verbatim: false,\n };\n}\n\n/**\n * Display parts for a locale, respecting the plugin's custom locale mapping.\n * Uses the bare language name plus the locale code so regional variants read\n * as e.g. `πŸ‡ΊπŸ‡Έ English (en-US)` instead of `American English`.\n */\nexport function getLocaleDisplay(localeId: string): LocaleDisplay {\n return localeDisplayFromProperties(\n localeId,\n gt.getLocaleProperties(localeId),\n gt.customMapping?.[localeId]\n );\n}\n\n/** Single-string form built from precomputed properties. */\nexport function formatLocalePropertiesLabel(\n code: string,\n properties: LocaleProperties,\n mapping?: CustomMappingEntry\n): string {\n const { emoji, name, verbatim } = localeDisplayFromProperties(\n code,\n properties,\n mapping\n );\n if (verbatim) return name;\n return [emoji, `${name} (${code})`].filter(Boolean).join(' ');\n}\n\n/** Single-string form, e.g. `πŸ‡ΊπŸ‡Έ English (en-US)`. */\nexport function formatLocaleLabel(localeId: string): string {\n return formatLocalePropertiesLabel(\n localeId,\n gt.getLocaleProperties(localeId),\n gt.customMapping?.[localeId]\n );\n}\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { SanityClient, useClient as useSanityClient } from 'sanity';\nimport { SANITY_API_VERSION } from '../utils/shared';\n\nexport const useClient = (): SanityClient => {\n return useSanityClient({ apiVersion: SANITY_API_VERSION });\n};\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { useState, useEffect } from 'react';\nimport { SanityDocumentLike } from 'sanity';\nimport { useClient } from './useClient';\n\ninterface ReturnProps<T> {\n loading: boolean;\n secrets: T | null;\n}\nexport function useSecrets<T>(id: string): ReturnProps<T> {\n const [loading, setLoading] = useState<boolean>(true);\n const [secrets, setSecrets] = useState<T | null>(null);\n const client = useClient();\n\n useEffect(() => {\n function fetchData() {\n client\n .fetch('* [_id == $id][0]', { id })\n .then((doc: SanityDocumentLike) => {\n const result: Record<string, unknown> = {};\n for (const key in doc) {\n if (key[0] !== '_') {\n result[key] = doc[key];\n }\n }\n setSecrets(result as T);\n setLoading(false);\n });\n }\n fetchData();\n }, [id, client]);\n\n return { loading, secrets };\n}\n","import React from 'react';\nimport { ThemeProvider, Box, Card, Flex, Spinner, Text } from '@sanity/ui';\nimport { ToastProvider } from '@sanity/ui/toast';\nimport { buildTheme } from '@sanity/ui/theme';\nimport { useSecrets } from '../../hooks/useSecrets';\nimport { Secrets } from '../../types';\nimport { pluginConfig } from '../../adapter/core';\n\n// GT's design system rounds nearly every surface to 6px (rounded-md). Bump\n// the default radius steps so plugin buttons/cards/inputs match without\n// having to set `radius` on every component.\nconst gtRadius = [0, 4, 6, 8, 12, 16, 24];\nconst baseTheme = buildTheme();\nconst theme = {\n ...baseTheme,\n radius: gtRadius,\n v2: baseTheme.v2 && { ...baseTheme.v2, radius: gtRadius },\n};\n\ninterface BaseTranslationWrapperProps {\n children: React.ReactNode;\n secretsNamespace?: string;\n padding?: number;\n showContainer?: boolean;\n}\n\nexport const BaseTranslationWrapper: React.FC<BaseTranslationWrapperProps> = ({\n children,\n secretsNamespace = pluginConfig.getSecretsNamespace(),\n padding = 4,\n showContainer = true,\n}) => {\n const { loading: loadingSecrets, secrets } =\n useSecrets<Secrets>(secretsNamespace);\n\n const content = (\n <>\n {loadingSecrets && (\n <Flex padding={5} align='center' justify='center'>\n <Spinner />\n </Flex>\n )}\n\n {!loadingSecrets && !secrets && (\n <Box padding={padding}>\n <Card tone='caution' padding={[2, 3, 4, 4]} shadow={1} radius={2}>\n <Text>\n Can't find secrets for your translation service. Did you load them\n into this dataset?\n </Text>\n </Card>\n </Box>\n )}\n\n {!loadingSecrets && secrets && children}\n </>\n );\n\n return (\n <ThemeProvider theme={theme}>\n <ToastProvider paddingY={7}>\n {showContainer ? <Box padding={padding}>{content}</Box> : content}\n </ToastProvider>\n </ThemeProvider>\n );\n};\n\nexport interface UseTranslationSecretsResult {\n loadingSecrets: boolean;\n secrets: Secrets | null;\n}\n\nexport const useTranslationSecrets = (\n secretsNamespace?: string\n): UseTranslationSecretsResult => {\n const { loading: loadingSecrets, secrets } = useSecrets<Secrets>(\n secretsNamespace || 'translationService.secrets'\n );\n\n return {\n loadingSecrets,\n secrets,\n };\n};\n","// Adapted from https://github.com/sanity-io/sanity-naive-html-serializer\n\nimport { Merger } from './types';\nimport { SanityDocument } from 'sanity';\nimport { extractWithPath, arrayToJSONMatchPath } from '@sanity/mutator';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst reconcileArray = (\n origArray: unknown[],\n translatedArray: unknown[]\n): unknown[] => {\n //arrays of strings don't have keys, so just replace the array and return\n if (translatedArray && translatedArray.some((el) => typeof el === 'string')) {\n return translatedArray;\n }\n\n //deep copy needed for field level patching\n const combined = JSON.parse(JSON.stringify(origArray)) as unknown[];\n\n translatedArray.forEach((translatedItem) => {\n if (!isRecord(translatedItem) || !translatedItem._key) {\n return;\n }\n const foundBlockIdx = origArray.findIndex(\n (origBlock) =>\n isRecord(origBlock) && origBlock._key === translatedItem._key\n );\n if (foundBlockIdx < 0) {\n //eslint-disable-next-line no-console\n console.warn(\n `This block no longer exists on the original document. Was it removed? ${JSON.stringify(\n translatedItem\n )}`\n );\n } else if (\n isRecord(origArray[foundBlockIdx]) &&\n (origArray[foundBlockIdx]._type === 'block' ||\n origArray[foundBlockIdx]._type === 'span')\n ) {\n combined[foundBlockIdx] = translatedItem;\n } else if (isRecord(origArray[foundBlockIdx])) {\n combined[foundBlockIdx] = reconcileObject(\n origArray[foundBlockIdx],\n translatedItem\n );\n }\n });\n return combined;\n};\n\nconst reconcileObject = (\n origObject: Record<string, unknown>,\n translatedObject: Record<string, unknown>\n): Record<string, unknown> => {\n if (\n typeof translatedObject !== 'object' ||\n !Object.keys(translatedObject).length\n ) {\n return origObject;\n }\n\n const updatedObj = JSON.parse(JSON.stringify(origObject)) as Record<\n string,\n unknown\n >;\n Object.entries(translatedObject).forEach(([key, value]) => {\n if (!value || key[0] === '_') {\n return;\n }\n if (typeof value === 'string') {\n updatedObj[key] = value;\n } else if (Array.isArray(value)) {\n updatedObj[key] = reconcileArray(\n Array.isArray(origObject[key]) ? origObject[key] : [],\n value\n );\n } else if (isRecord(value)) {\n updatedObj[key] = reconcileObject(\n isRecord(origObject[key]) ? origObject[key] : {},\n value\n );\n }\n });\n return updatedObj;\n};\n\nconst fieldLevelMerge = (\n translatedFields: Record<string, unknown>,\n //should be fetched according to the revision and id of the translated obj above\n baseDoc: SanityDocument,\n localeId: string,\n baseLang: string = libraryDefaultLocale\n): Record<string, unknown> => {\n const merged: Record<string, unknown> = {};\n const metaKeys = ['_rev', '_id', '_type'];\n metaKeys.forEach((metaKey) => {\n if (translatedFields[metaKey]) {\n merged[metaKey] = translatedFields[metaKey];\n }\n });\n\n //get any field that matches the base language, because it's been translated\n const originPaths = extractWithPath(`..${baseLang}`, translatedFields);\n originPaths.forEach((match) => {\n const origVal = extractWithPath(\n arrayToJSONMatchPath(match.path),\n baseDoc\n )[0].value;\n const translatedVal = extractWithPath(\n arrayToJSONMatchPath(match.path),\n translatedFields\n )[0].value;\n let valToPatch;\n if (typeof translatedVal === 'string') {\n valToPatch = translatedVal;\n } else if (Array.isArray(translatedVal) && translatedVal.length) {\n valToPatch = reconcileArray(\n (origVal as Array<unknown>) ?? [],\n translatedVal\n );\n } else if (\n typeof translatedVal === 'object' &&\n Object.keys(translatedVal as Record<string, unknown>).length\n ) {\n valToPatch = reconcileObject(\n isRecord(origVal) ? origVal : {},\n translatedVal as Record<string, unknown>\n );\n }\n const destinationPath = [\n ...match.path.slice(0, match.path.length - 1), //cut off the \"en\"\n localeId.replace('-', '_'), // replace it with our locale\n ];\n\n merged[arrayToJSONMatchPath(destinationPath)] = valToPatch;\n });\n\n return merged;\n};\n\nconst documentLevelMerge = <\n TTranslatedFields extends Record<string, unknown>,\n TBaseDoc extends SanityDocument,\n>(\n translatedFields: TTranslatedFields,\n //should be fetched according to the revision and id of the translated obj above\n baseDoc: TBaseDoc\n): TBaseDoc & TTranslatedFields => {\n return reconcileObject(\n baseDoc as Record<string, unknown>,\n translatedFields\n ) as TBaseDoc & TTranslatedFields;\n};\n\nexport const BaseDocumentMerger: Merger = {\n fieldLevelMerge,\n documentLevelMerge,\n reconcileArray,\n reconcileObject,\n};\n","import type { SanityDocument } from 'sanity';\n\nexport function getPublishedId(documentId: string): string {\n return documentId.startsWith('drafts.') ? documentId.slice(7) : documentId;\n}\n\nexport function getDocumentPublishedId(document: SanityDocument): string {\n return getPublishedId(document._id);\n}\n\nexport function dedupeDocumentsPreferDraft<T extends SanityDocument>(\n documents: T[]\n): T[] {\n const byPublishedId = new Map<string, T>();\n\n for (const document of documents) {\n const publishedId = getDocumentPublishedId(document);\n const existing = byPublishedId.get(publishedId);\n\n if (!existing || document._id.startsWith('drafts.')) {\n byPublishedId.set(publishedId, document);\n }\n }\n\n return Array.from(byPublishedId.values());\n}\n\nexport function createTranslationStatusKey(\n branchId: string | undefined,\n documentId: string,\n versionId: string,\n localeId: string\n): string {\n const publishedId = getPublishedId(documentId);\n return branchId\n ? `${branchId}:${publishedId}:${versionId}:${localeId}`\n : `${publishedId}:${versionId}:${localeId}`;\n}\n\nexport function createStableTranslationKey(\n branchId: string | undefined,\n documentId: string,\n localeId: string\n): string {\n const publishedId = getPublishedId(documentId);\n return branchId\n ? `${branchId}:${publishedId}:${localeId}`\n : `${publishedId}:${localeId}`;\n}\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { SanityClient, SanityDocument } from 'sanity';\nimport { getPublishedId } from '../../utils/documentIds';\n\n/**\n * Resolves the draft for a document id, falling back to the published copy.\n * Returns `undefined` when neither exists.\n */\nexport const findLatestDraft = (\n documentId: string,\n client: SanityClient\n): Promise<SanityDocument | undefined> => {\n const publishedId = getPublishedId(documentId);\n const query = `*[_id == $id || _id == $draftId]`;\n const params = { id: publishedId, draftId: `drafts.${publishedId}` };\n return client\n .fetch(query, params)\n .then(\n (docs: SanityDocument[]) =>\n docs.find((doc) => doc._id.startsWith('drafts.')) ?? docs[0]\n );\n};\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { SanityClient, SanityDocument } from 'sanity';\n\n//revision fetch\nexport const findDocumentAtRevision = async (\n documentId: string,\n rev: string,\n client: SanityClient\n): Promise<SanityDocument> => {\n const dataset = client.config().dataset;\n const baseUrl = `/data/history/${dataset}/documents/${documentId}?revision=${rev}`;\n const url = client.getUrl(baseUrl);\n const revisionDoc = await fetch(url, { credentials: 'include' })\n .then((req) => req.json())\n .then((req) => {\n if (req.documents && req.documents.length) {\n return req.documents[0];\n }\n return null;\n });\n\n return revisionDoc;\n};\n","import { SanityClient, SanityDocument } from 'sanity';\nimport { createDiagnosticMessage } from 'generaltranslation/internal';\nimport { findLatestDraft } from './findLatestDraft';\nimport { findDocumentAtRevision } from './findDocumentAtRevision';\n\n/**\n * Resolves the document a translation is written against, preferring the\n * revision the translation was produced from and falling back to the latest\n * draft or published copy.\n *\n * Throws when nothing resolves.\n */\nexport async function requireSourceDocument(\n documentId: string,\n versionId: string | undefined,\n client: SanityClient\n): Promise<SanityDocument> {\n let doc: SanityDocument | null | undefined = null;\n\n if (documentId && versionId) {\n doc = await findDocumentAtRevision(documentId, versionId, client);\n }\n if (!doc) {\n doc = await findLatestDraft(documentId, client);\n }\n if (!doc) {\n throw new Error(missingDocumentDiagnostic(documentId));\n }\n\n return doc;\n}\n\n/**\n * Resolves a document that must already exist, without the revision lookup.\n */\nexport async function requireLatestDraft(\n documentId: string,\n client: SanityClient\n): Promise<SanityDocument> {\n const doc = await findLatestDraft(documentId, client);\n if (!doc) {\n throw new Error(missingDocumentDiagnostic(documentId));\n }\n return doc;\n}\n\nfunction missingDocumentDiagnostic(documentId: string): string {\n return createDiagnosticMessage({\n source: 'gt-sanity',\n severity: 'Error',\n whatHappened: 'Could not find the document to translate',\n why: 'no draft or published version of it exists in this dataset',\n fix: 'Check that the document was not deleted, and that the Studio is pointed at the dataset that holds it',\n details: [`Document ID: ${documentId}`],\n });\n}\n","import { JSONPath } from 'jsonpath-plus';\nimport JSONPointer from 'jsonpointer';\nimport type { DedupeFields, FieldMatcher, SkipFields } from '../adapter/types';\n\nexport function forEachMatchingField(\n documentId: string,\n document: Record<string, unknown>,\n fields: FieldMatcher[],\n callback: (result: {\n pointer: string;\n value: unknown;\n parent: Record<string, unknown> | unknown[];\n parentProperty: string;\n }) => void\n): void {\n const applicable = fields.filter(\n (field) =>\n field.documentId === documentId ||\n field.documentId === undefined ||\n field.documentId === null\n );\n\n for (const entry of applicable) {\n if (!entry.fields) continue;\n\n for (const field of entry.fields) {\n const { property, type } = field;\n\n try {\n const results = JSONPath({\n json: document,\n path: property,\n resultType: 'all',\n flatten: true,\n wrap: true,\n });\n\n if (results && results.length > 0) {\n results.forEach(\n (result: {\n pointer: string;\n value: unknown;\n parent: Record<string, unknown> | unknown[];\n parentProperty: string;\n }) => {\n if (type !== undefined) {\n if (\n typeof result.value === 'object' &&\n result.value !== null &&\n !Array.isArray(result.value) &&\n (result.value as Record<string, unknown>)._type === type\n ) {\n callback(result);\n }\n } else {\n callback(result);\n }\n }\n );\n }\n } catch (error) {\n console.warn(`Invalid JSONPath: ${property}`, error);\n }\n }\n }\n}\n\nexport function deleteMatchingFields(\n documentId: string,\n document: Record<string, unknown>,\n fields: FieldMatcher[]\n): void {\n const arrayRemovals: Array<{ parent: unknown[]; index: number }> = [];\n\n forEachMatchingField(documentId, document, fields, (result) => {\n if (Array.isArray(result.parent)) {\n arrayRemovals.push({\n parent: result.parent,\n index: Number(result.parentProperty),\n });\n } else {\n delete result.parent[result.parentProperty];\n }\n });\n\n // Splice array elements in reverse index order to avoid shifting indices\n arrayRemovals.sort((a, b) => b.index - a.index);\n for (const { parent, index } of arrayRemovals) {\n parent.splice(index, 1);\n }\n}\n\nexport function applyDocuments(\n documentId: string,\n sourceDocument: Record<string, unknown>,\n targetDocument: Record<string, unknown>,\n ignore: FieldMatcher[],\n skip: SkipFields[] = [],\n dedupe: DedupeFields[] = [],\n localeId?: string\n) {\n // Deep copy both documents so mutations (e.g. skip-field deletions) never affect the originals\n const mergedDocument = JSON.parse(JSON.stringify(sourceDocument));\n\n // Merge top-level properties of targetDocument\n const clonedTarget = JSON.parse(JSON.stringify(targetDocument));\n for (const [key, value] of Object.entries(clonedTarget)) {\n mergedDocument[key] = value;\n }\n\n // Restore ignored fields from source document\n forEachMatchingField(documentId, sourceDocument, ignore, (result) => {\n JSONPointer.set(mergedDocument, result.pointer, result.value);\n });\n\n // Restore de-duped fields from the source document with a deterministic locale suffix.\n forEachMatchingField(documentId, sourceDocument, dedupe, (result) => {\n JSONPointer.set(\n mergedDocument,\n result.pointer,\n dedupeFieldValue(result.value, localeId)\n );\n });\n\n // Remove skip fields from merged document\n deleteMatchingFields(documentId, mergedDocument, skip);\n\n return mergedDocument;\n}\n\nfunction dedupeFieldValue(value: unknown, localeId?: string): unknown {\n if (!localeId) return value;\n\n if (typeof value === 'string') {\n return appendLocaleSuffix(value, localeId);\n }\n\n if (\n value &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n typeof (value as Record<string, unknown>).current === 'string'\n ) {\n const slug = value as Record<string, unknown>;\n return {\n ...slug,\n current: appendLocaleSuffix(slug.current as string, localeId),\n };\n }\n\n return value;\n}\n\nfunction appendLocaleSuffix(value: string, localeId: string): string {\n if (!value) return value;\n\n const suffix = createLocaleSuffix(localeId);\n if (!suffix || value.endsWith(suffix)) return value;\n\n return `${value}${suffix}`;\n}\n\nfunction createLocaleSuffix(localeId: string): string {\n const normalized = localeId\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n\n return normalized ? `-${normalized}` : '';\n}\n","export function randomKey(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n","/**\n * GROQ fragments for reading `translation.metadata` documents, single-sourced\n * so every query stays in sync with the write path\n * (`createI18nDocAndPatchMetadata` / `getOrCreateTranslationMetadata`).\n *\n * The locale of each `translations[]` entry lives in its literal `language`\n * property. That is the storage shape of the metadata document itself and is\n * unrelated to the configurable `languageField` option, which only renames\n * the language field on content documents.\n */\nexport const TRANSLATION_METADATA_TYPE = 'translation.metadata';\n\n/** Deterministic metadata document id for a source document. */\nexport function translationMetadataId(publishedDocumentId: string): string {\n return `${TRANSLATION_METADATA_TYPE}.${publishedDocumentId}`;\n}\n\n/**\n * `translations[]` entries whose `language` matches a GROQ condition, e.g.\n * `metadataTranslations('== $sourceLocale')` or\n * `metadataTranslations('in $localeIds', 'defined(value._ref)')`.\n */\nexport function metadataTranslations(\n languageCondition: string,\n extraCondition?: string\n): string {\n return `translations[language ${languageCondition}${\n extraCondition ? ` && ${extraCondition}` : ''\n }]`;\n}\n\n/**\n * The `_ref` of the document recorded for a language, e.g.\n * `metadataTranslationRef('$sourceLocale')`.\n */\nexport function metadataTranslationRef(languageExpression: string): string {\n return `${metadataTranslations(`== ${languageExpression}`)}[0].value._ref`;\n}\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { SanityClient, SanityDocumentLike } from 'sanity';\nimport { pluginConfig } from '../../../adapter/core';\nimport { applyDocuments } from '../../../utils/applyDocuments';\nimport { getPublishedId } from '../../../utils/documentIds';\nimport { randomKey } from '../../../utils/randomKey';\nimport { metadataTranslations } from '../../../utils/translationMetadata';\n\nexport async function createI18nDocAndPatchMetadata(\n sourceDocument: SanityDocumentLike,\n translatedDoc: SanityDocumentLike,\n localeId: string,\n client: SanityClient,\n translationMetadata: SanityDocumentLike,\n sourceDocumentId: string,\n languageField: string = 'language'\n): Promise<void> {\n const publishedSourceDocumentId = getPublishedId(sourceDocumentId);\n translatedDoc[languageField] = localeId;\n const translations = translationMetadata.translations as Record<\n string,\n unknown\n >[];\n const existingLocaleKey = translations.find(\n (translation) => translation.language === localeId\n );\n const operation = existingLocaleKey ? 'replace' : 'after';\n const location = existingLocaleKey\n ? metadataTranslations(`== \"${localeId}\"`)\n : 'translations[-1]';\n\n //remove system fields\n const { _updatedAt, _createdAt, ...rest } = translatedDoc;\n\n const appliedDocument = applyDocuments(\n publishedSourceDocumentId,\n sourceDocument,\n rest,\n pluginConfig.getIgnoreFields(),\n pluginConfig.getSkipFields(),\n pluginConfig.getDedupeFields(),\n localeId\n );\n\n // Check if this is a singleton document and apply singleton mapping\n const singletons = pluginConfig.getSingletons();\n const isSingleton = singletons.includes(publishedSourceDocumentId);\n\n let createDocumentPromise;\n if (isSingleton) {\n const singletonMapping = pluginConfig.getSingletonMapping();\n const translatedDocId = singletonMapping(\n publishedSourceDocumentId,\n localeId\n );\n createDocumentPromise = client.create({\n ...appliedDocument,\n _type: rest._type,\n _id: `drafts.${translatedDocId}`,\n });\n } else {\n createDocumentPromise = client.create({\n ...appliedDocument,\n _type: rest._type,\n _id: 'drafts.',\n });\n }\n\n const doc = await createDocumentPromise;\n const _ref = getPublishedId(doc._id);\n await client\n .transaction()\n .patch(translationMetadata._id, (p) =>\n p.insert(operation, location, [\n {\n _key: randomKey(),\n language: localeId,\n _type: 'internationalizedArrayReferenceValue',\n value: {\n _type: 'reference',\n _ref,\n _weak: true,\n _strengthenOnPublish: {\n type: doc._type,\n },\n },\n },\n ])\n )\n .commit();\n}\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport {\n KeyedObject,\n Reference,\n SanityClient,\n SanityDocumentLike,\n} from 'sanity';\nimport { randomKey } from '../../../utils/randomKey';\nimport { getPublishedId } from '../../../utils/documentIds';\nimport {\n metadataTranslationRef,\n translationMetadataId,\n TRANSLATION_METADATA_TYPE,\n} from '../../../utils/translationMetadata';\n\ntype TranslationReference = KeyedObject & {\n _type: 'internationalizedArrayReferenceValue';\n value: Reference;\n};\n\nexport const getOrCreateTranslationMetadata = async (\n documentId: string,\n baseDocument: SanityDocumentLike,\n client: SanityClient,\n baseLanguage: string\n): Promise<SanityDocumentLike> => {\n const publishedId = getPublishedId(documentId);\n\n // First, try to get existing metadata\n const existingMetadata = await client.fetch(\n `*[\n _type == '${TRANSLATION_METADATA_TYPE}' &&\n ${metadataTranslationRef('$baseLanguage')} == $id\n ][0]`,\n { baseLanguage, id: publishedId }\n );\n\n if (existingMetadata) {\n return existingMetadata;\n }\n\n // If no metadata exists, create it atomically\n const baseLangEntry: TranslationReference = {\n _key: randomKey(),\n language: baseLanguage,\n _type: 'internationalizedArrayReferenceValue',\n value: {\n _type: 'reference',\n _ref: getPublishedId(baseDocument._id),\n },\n };\n\n if (baseDocument._id.startsWith('drafts.')) {\n baseLangEntry.value = {\n ...baseLangEntry.value,\n _weak: true,\n //this should reflect doc i18n config when this\n //plugin is able to take that as a config option\n _strengthenOnPublish: {\n type: baseDocument._type,\n },\n };\n }\n\n try {\n // Use createIfNotExists to handle race conditions\n return await client.createIfNotExists({\n _id: translationMetadataId(publishedId),\n _type: TRANSLATION_METADATA_TYPE,\n translations: [baseLangEntry],\n });\n } catch (error) {\n // If creation fails due to race condition, fetch the existing document\n const metadata = await client.fetch(\n `*[\n _type == '${TRANSLATION_METADATA_TYPE}' &&\n ${metadataTranslationRef('$baseLanguage')} == $id\n ][0]`,\n { baseLanguage, id: publishedId }\n );\n\n if (metadata) {\n return metadata;\n }\n\n throw error;\n }\n};\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { SanityClient, SanityDocumentLike } from 'sanity';\nimport JSONPointer from 'jsonpointer';\nimport {\n applyDocuments,\n deleteMatchingFields,\n forEachMatchingField,\n} from '../../../utils/applyDocuments';\nimport { pluginConfig } from '../../../adapter/core';\nimport { getPublishedId } from '../../../utils/documentIds';\n\nconst SYSTEM_FIELDS = ['_id', '_rev', '_updatedAt', 'language'];\n\nconst isSystemField = (field: string) => SYSTEM_FIELDS.includes(field);\n\nexport async function patchI18nDoc(\n sourceDocumentId: string,\n i18nDocId: string,\n sourceDocument: SanityDocumentLike,\n mergedDocument: SanityDocumentLike,\n translatedFields: Record<string, unknown>,\n client: SanityClient,\n existingDocument?: SanityDocumentLike\n): Promise<void> {\n const cleanedMerge: Record<string, unknown> = {};\n Object.entries(mergedDocument).forEach(([key, value]) => {\n if (\n //only patch those fields that had translated strings\n key in translatedFields &&\n //don't overwrite any existing system values on the i18n doc\n !isSystemField(key)\n ) {\n cleanedMerge[key] = value;\n }\n });\n const cleanedSourceDocument: Record<string, unknown> = {};\n Object.entries(sourceDocument).forEach(([key, value]) => {\n if (\n // extract only the fields that are not system fields\n !isSystemField(key)\n ) {\n cleanedSourceDocument[key] = value;\n }\n });\n const appliedDocument = applyDocuments(\n sourceDocumentId,\n cleanedSourceDocument,\n cleanedMerge,\n pluginConfig.getIgnoreFields(),\n pluginConfig.getSkipFields()\n );\n const dedupeFields = pluginConfig.getDedupeFields();\n deleteMatchingFields(sourceDocumentId, appliedDocument, dedupeFields);\n if (existingDocument) {\n forEachMatchingField(\n sourceDocumentId,\n existingDocument,\n dedupeFields,\n (result) => {\n JSONPointer.set(appliedDocument, result.pointer, result.value);\n }\n );\n }\n if (i18nDocId.startsWith('drafts.')) {\n await client.patch(i18nDocId, { set: appliedDocument }).commit();\n return;\n }\n\n // A draft in Sanity is just a document whose id carries a `drafts.` prefix,\n // and the client writes to whatever id it is handed β€” it will not redirect a\n // write to the draft on your behalf. A published id here is therefore the\n // copy readers are served. Copy it into a draft and patch that, so the\n // translation lands somewhere reviewable and the live document only changes\n // when someone publishes.\n const seed = existingDocument ?? (await client.getDocument(i18nDocId));\n if (!seed) {\n // References in `translation.metadata` are weak, so they outlive the\n // documents they point at: deleting a translation leaves its entry behind.\n // With no document to copy there is nothing to seed a draft from, so patch\n // the id directly and let the missing document surface as an error.\n await client.patch(i18nDocId, { set: appliedDocument }).commit();\n return;\n }\n\n const draftId = `drafts.${getPublishedId(i18nDocId)}`;\n await client\n .transaction()\n .createIfNotExists({ ...seed, _id: draftId })\n .patch(draftId, (patch) => patch.set(appliedDocument))\n .commit();\n}\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { SanityClient, SanityDocument, SanityDocumentLike } from 'sanity';\nimport { BaseDocumentMerger } from '../../serialization/BaseDocumentMerger';\n\nimport { findLatestDraft } from '../utils/findLatestDraft';\nimport { requireSourceDocument } from '../utils/requireSourceDocument';\nimport { createI18nDocAndPatchMetadata } from './helpers/createI18nDocAndPatchMetadata';\nimport { getOrCreateTranslationMetadata } from './helpers/getOrCreateTranslationMetadata';\nimport { patchI18nDoc } from './helpers/patchI18nDoc';\nimport type { GTFile } from '../../types';\nimport { pluginConfig } from '../../adapter/core';\n\ntype TranslationReference = {\n language?: string;\n value?: {\n _ref?: string;\n };\n};\n\nexport const documentLevelPatch = async (\n docInfo: GTFile,\n translatedFields: SanityDocument,\n localeId: string,\n client: SanityClient,\n languageField: string = 'language',\n mergeWithTargetLocale: boolean = false\n): Promise<void> => {\n const baseLanguage = pluginConfig.getSourceLocale();\n\n //this is the document that will serve as the translated doc\n let i18nDoc: SanityDocument | undefined;\n\n /*\n * we send over the _rev with our translation file so we can\n * accurately coalesce the translations in case something has\n * changed in the base document since translating\n */\n //this is the document we use to merge with the translated fields\n let baseDoc = await requireSourceDocument(\n docInfo.documentId,\n docInfo.versionId,\n client\n );\n\n /* first, check our metadata to see if a translated document exists\n * if no metadata exists, we create it atomically\n */\n const translationMetadata = await getOrCreateTranslationMetadata(\n docInfo.documentId,\n baseDoc,\n client,\n baseLanguage\n );\n\n //the id of the translated document should be on the metadata if it exists\n const translations =\n translationMetadata.translations as TranslationReference[];\n const i18nDocId = translations.find(\n (translation) => translation.language === localeId\n )?.value?._ref;\n\n if (i18nDocId) {\n //get draft or published\n i18nDoc = await findLatestDraft(i18nDocId, client);\n }\n\n //if the user has chosen to merge with the target locale,\n //any existing target document will serve as our base document\n if (mergeWithTargetLocale && i18nDoc) {\n baseDoc = i18nDoc;\n } else if (docInfo.documentId && docInfo.versionId) {\n /*\n * we send over the _rev with our translation file so we can\n * accurately coalesce the translations in case something has\n * changed in the base document since translating\n */\n baseDoc = await requireSourceDocument(\n docInfo.documentId,\n docInfo.versionId,\n client\n );\n }\n /*\n * we then merge the translation with the base document\n * to create a document that contains the translation and everything\n * that wasn't sent over for translation\n */\n const merged = BaseDocumentMerger.documentLevelMerge(\n translatedFields,\n baseDoc\n ) as SanityDocumentLike;\n\n if (i18nDoc) {\n await patchI18nDoc(\n docInfo.documentId,\n i18nDoc._id,\n baseDoc,\n merged,\n translatedFields,\n client,\n i18nDoc\n );\n }\n //otherwise, create a new document\n //and add the document reference to the metadata document\n else {\n const freshTranslationMetadata = await getOrCreateTranslationMetadata(\n docInfo.documentId,\n baseDoc,\n client,\n baseLanguage\n );\n const freshTranslations =\n freshTranslationMetadata.translations as TranslationReference[];\n const freshI18nDocId = freshTranslations.find(\n (translation) => translation.language === localeId\n )?.value?._ref;\n\n const freshI18nDoc = freshI18nDocId\n ? await findLatestDraft(freshI18nDocId, client)\n : undefined;\n\n if (freshI18nDoc) {\n await patchI18nDoc(\n docInfo.documentId,\n freshI18nDoc._id,\n baseDoc,\n merged,\n translatedFields,\n client,\n freshI18nDoc\n );\n return;\n }\n\n /*\n * A metadata entry for this locale can outlive the document it points at.\n * Since the references are weak, deleting a translation leaves the entry\n * behind.\n *\n * `createI18nDocAndPatchMetadata` replaces the existing entry for the\n * locale.\n */\n await createI18nDocAndPatchMetadata(\n baseDoc,\n merged,\n localeId,\n client,\n freshTranslationMetadata,\n docInfo.documentId,\n languageField\n );\n }\n};\n","// Helpers for recognising the `sanity-plugin-internationalized-array` storage\n// shape, where a localized field is stored as an array of per-locale items:\n//\n// title: [\n// { _key: 'abc', _type: 'internationalizedArrayStringValue', language: 'en', value: 'Hello' },\n// { _key: 'def', _type: 'internationalizedArrayStringValue', language: 'es', value: 'Hola' },\n// ]\n//\n// Detection is shape-based (not schema-based) so the serializer/merger do not\n// have to thread the schema through every call, but it is anchored on the\n// value `_type` naming convention (`internationalizedArray…Value`) so\n// user-defined types that merely share the `{ language, value }` shape are\n// not misdetected. The prefix is fixed by sanity-plugin-internationalized-array.\nconst TYPE_PREFIX = 'internationalizedArray';\n\nexport const isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nexport type InternationalizedArrayItem = {\n _key?: string;\n _type: string;\n language: string;\n value: unknown;\n};\n\n/**\n * A single `{ _key, _type, language, value }` entry. The `_type` of the\n * generated value objects is always `internationalizedArray<FieldType>Value`\n * (e.g. `internationalizedArrayStringValue`), so both the prefix and the\n * `Value` suffix are required β€” a bare `endsWith('Value')` check would\n * misdetect user-defined types like `priceValue` that happen to carry\n * `language`/`value` keys.\n */\nexport function isInternationalizedArrayItem(\n item: unknown\n): item is InternationalizedArrayItem {\n return (\n isRecord(item) &&\n typeof item._type === 'string' &&\n item._type.startsWith(TYPE_PREFIX) &&\n item._type.endsWith('Value') &&\n typeof item.language === 'string' &&\n 'value' in item\n );\n}\n\n/**\n * A non-empty array where every element is an internationalized-array item.\n */\nexport function isInternationalizedArrayField(\n value: unknown\n): value is InternationalizedArrayItem[] {\n return (\n Array.isArray(value) &&\n value.length > 0 &&\n value.every(isInternationalizedArrayItem)\n );\n}\n\n/**\n * Returns the item for a given locale, matching on the exact `language` id\n * (hyphens preserved, e.g. `fr-CA`). Never matches on `_key`, which is random.\n */\nexport function findLocaleItem(\n field: InternationalizedArrayItem[],\n locale: string\n): InternationalizedArrayItem | undefined {\n return field.find((item) => item.language === locale);\n}\n\n/**\n * Whether any internationalized-array field anywhere in the value has an item\n * for the given locale. Used to skip locales with no existing content instead\n * of uploading an empty translation.\n */\nexport function hasLocaleContent(value: unknown, locale: string): boolean {\n if (isInternationalizedArrayField(value)) {\n return findLocaleItem(value, locale) !== undefined;\n }\n\n if (Array.isArray(value)) {\n return value.some((item) => hasLocaleContent(item, locale));\n }\n\n if (isRecord(value)) {\n return Object.values(value).some((item) => hasLocaleContent(item, locale));\n }\n\n return false;\n}\n","import { randomKey } from '../../utils/randomKey';\nimport {\n findLocaleItem,\n InternationalizedArrayItem,\n isInternationalizedArrayField,\n isRecord,\n} from './detect';\n\n/**\n * Upsert the translated value for `targetLocale` into an internationalized\n * array, preserving every other locale item and its (random) `_key`.\n *\n * Sanity mutations can only address array items by `_key`, and `_key` is random\n * here, so we resolve the target item by its `language` field and reuse its\n * existing `_key`; if absent we append a fresh random `_key`.\n */\nfunction upsertLocaleItem(\n baseArray: InternationalizedArrayItem[],\n translatedValue: unknown,\n targetLocale: string,\n sourceLocale: string\n): InternationalizedArrayItem[] {\n const itemType = (findLocaleItem(baseArray, sourceLocale) ?? baseArray[0])\n ._type;\n\n const updated = baseArray.map((item) =>\n item.language === targetLocale\n ? { ...item, value: translatedValue }\n : { ...item }\n );\n\n if (!findLocaleItem(updated, targetLocale)) {\n updated.push({\n _key: randomKey(),\n _type: itemType,\n language: targetLocale,\n value: translatedValue,\n });\n }\n\n return updated;\n}\n\n/**\n * Merge a single base value with its translated counterpart, returning the new\n * value to write, or `undefined` when nothing localized changed at this level.\n * Recurses through plain objects (by key) and plain arrays (by `_key`) so\n * internationalized-array fields nested inside other content are also handled.\n */\nfunction mergeValue(\n baseValue: unknown,\n translatedValue: unknown,\n targetLocale: string,\n sourceLocale: string\n): unknown {\n if (isInternationalizedArrayField(baseValue)) {\n return upsertLocaleItem(\n baseValue,\n translatedValue,\n targetLocale,\n sourceLocale\n );\n }\n\n if (Array.isArray(baseValue) && Array.isArray(translatedValue)) {\n let changed = false;\n const merged = baseValue.map((item) => {\n if (!isRecord(item) || typeof item._key !== 'string') {\n return item;\n }\n const translatedItem = translatedValue.find(\n (candidate) => isRecord(candidate) && candidate._key === item._key\n );\n if (!translatedItem) {\n return item;\n }\n const mergedItem = mergeValue(\n item,\n translatedItem,\n targetLocale,\n sourceLocale\n );\n if (mergedItem !== undefined) {\n changed = true;\n return mergedItem;\n }\n return item;\n });\n return changed ? merged : undefined;\n }\n\n if (isRecord(baseValue) && isRecord(translatedValue)) {\n let changed = false;\n const merged: Record<string, unknown> = { ...baseValue };\n for (const key of Object.keys(translatedValue)) {\n if (key.startsWith('_') || !(key in baseValue)) {\n continue;\n }\n const mergedChild = mergeValue(\n baseValue[key],\n translatedValue[key],\n targetLocale,\n sourceLocale\n );\n if (mergedChild !== undefined) {\n merged[key] = mergedChild;\n changed = true;\n }\n }\n return changed ? merged : undefined;\n }\n\n return undefined;\n}\n\n/**\n * Compare a base Sanity document against a deserialized translation and produce\n * a patch object of top-level fields whose internationalized-array content\n * changed. Each entry is the full merged top-level value (with the target\n * locale upserted), suitable for `client.patch(id).set(changes)`.\n *\n * Only top-level fields that actually changed are returned, so unrelated\n * content and other locales are left untouched.\n */\nexport function mergeInternationalizedArrays(\n baseDoc: Record<string, unknown>,\n translatedFields: Record<string, unknown>,\n targetLocale: string,\n sourceLocale: string\n): Record<string, unknown> {\n const changes: Record<string, unknown> = {};\n\n for (const key of Object.keys(translatedFields)) {\n if (key.startsWith('_') || !(key in baseDoc)) {\n continue;\n }\n const merged = mergeValue(\n baseDoc[key],\n translatedFields[key],\n targetLocale,\n sourceLocale\n );\n if (merged !== undefined) {\n changes[key] = merged;\n }\n }\n\n return changes;\n}\n","import { SanityClient, SanityDocument } from 'sanity';\nimport { pluginConfig } from '../../adapter/core';\nimport { mergeInternationalizedArrays } from '../../serialization/internationalizedArray/merge';\nimport type { GTFile } from '../../types';\nimport { getPublishedId } from '../../utils/documentIds';\nimport { findLatestDraft } from '../utils/findLatestDraft';\n\n/**\n * Import a translated internationalized-array document in place.\n *\n * Unlike document-level import (which creates per-locale documents and tracks\n * translation metadata), array localization upserts the target-locale `value`\n * into the same source document. We read the latest draft so concurrent edits\n * to the source are not clobbered, merge only the changed top-level fields, and\n * commit a single patch.\n */\nexport const internationalizedArrayPatch = async (\n docInfo: GTFile,\n translatedFields: SanityDocument,\n localeId: string,\n client: SanityClient\n): Promise<void> => {\n const sourceLocale = pluginConfig.getSourceLocale();\n\n const baseDoc = await findLatestDraft(docInfo.documentId, client);\n if (!baseDoc) {\n return;\n }\n\n const changes = mergeInternationalizedArrays(\n baseDoc as Record<string, unknown>,\n translatedFields as Record<string, unknown>,\n localeId,\n sourceLocale\n );\n\n if (Object.keys(changes).length === 0) {\n return;\n }\n\n // Every key in `changes` already exists on the base document (merge only\n // returns existing fields), so a full `set` of the merged field is safe and\n // preserves all other locale items and their random `_key`s.\n if (baseDoc._id.startsWith('drafts.')) {\n await client.patch(baseDoc._id).set(changes).commit();\n return;\n }\n\n // Only the published document exists. Mutations via the client write to the\n // exact id given (drafts are a Studio convention, not created server-side),\n // so patch a draft seeded from the published state instead of publishing\n // translated content directly.\n const draftId = `drafts.${getPublishedId(baseDoc._id)}`;\n await client\n .transaction()\n .createIfNotExists({ ...baseDoc, _id: draftId })\n .patch(draftId, (patch) => patch.set(changes))\n .commit();\n};\n","// Adapted from https://github.com/sanity-io/sanity-naive-html-serializer\nimport { htmlToBlocks } from '@portabletext/block-tools';\nimport { Schema } from '@sanity/schema';\nimport { ObjectField, PortableTextSpan, PortableTextTextBlock } from 'sanity';\n\nconst defaultSchema = Schema.compile({\n name: 'default',\n types: [\n {\n type: 'object',\n name: 'default',\n fields: [\n {\n name: 'block',\n type: 'array',\n of: [{ type: 'block' }],\n },\n ],\n },\n ],\n});\n\nexport const blockContentType = defaultSchema\n .get('default')\n .fields.find((field: ObjectField) => field.name === 'block').type;\n\nexport const noSchemaWarning = (obj: Element): string =>\n `WARNING: Unfortunately the deserializer may have issues with this field or object: ${obj.className}.\n If it's a specific type, you may need to declare at the top level, or write a custom deserializer.`;\n\n//helper to handle messy input -- take advantage\n//of blockTools' sanitizing behavior for single strings\nexport const preprocess = (html: string): string => {\n const intermediateBlocks = htmlToBlocks(\n `<p>${html}</p>`,\n blockContentType\n ) as PortableTextTextBlock<PortableTextSpan>[];\n if (!intermediateBlocks.length) {\n throw new Error(`Error parsing string '${html}'`);\n }\n return intermediateBlocks[0].children[0].text;\n};\n","export function attachGTData(\n html: string,\n data: Record<string, unknown>,\n type: 'markDef'\n): string {\n // Parse the HTML string to find the first element\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n const firstElement = doc.body.firstElementChild;\n\n if (!firstElement) {\n // If no element found, return original HTML\n return html;\n }\n\n // Encode the data as base64 JSON\n const encodedData = encode(JSON.stringify({ [type]: data }));\n\n // Add the data-gt-internal attribute\n firstElement.setAttribute('data-gt-internal', encodedData);\n\n return firstElement.outerHTML;\n}\n\nexport function detachGTData(html: string): {\n html: string;\n data?: Record<'markDef', Record<string, unknown>>;\n} {\n // Parse the HTML string to find the first element\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n const firstElement = doc.body.firstElementChild;\n\n if (!firstElement) {\n // If no element found, return original HTML with no data\n return { html };\n }\n\n // Get the encoded data\n const encodedData = firstElement.getAttribute('data-gt-internal');\n\n let extractedData: Record<'markDef', Record<string, unknown>> | undefined;\n if (encodedData) {\n try {\n // Decode and parse the data\n const decodedData = decode(encodedData);\n extractedData = JSON.parse(decodedData);\n\n // Remove the data attribute to clean up the HTML\n firstElement.removeAttribute('data-gt-internal');\n } catch (error) {\n console.warn('Failed to decode GT internal data:', error);\n }\n }\n\n return {\n html: firstElement.outerHTML,\n data: extractedData,\n };\n}\n\n// Encode a string to base64\nexport function encode(data: string): string {\n // Browser path\n const bytes = new TextEncoder().encode(data);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n// Decode a base64 string to a string\nexport function decode(base64: string): string {\n // Browser path\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new TextDecoder().decode(bytes);\n}\n","// Adapted from https://github.com/sanity-io/sanity-naive-html-serializer\n\nimport type { PortableTextBlockStyle } from '@portabletext/types';\n\nimport {\n PortableTextBlockComponent,\n PortableTextListComponent,\n PortableTextListItemComponent,\n PortableTextMarkComponent,\n PortableTextHtmlComponents,\n} from '@portabletext/to-html';\n\nimport { htmlToBlocks } from '@portabletext/block-tools';\nimport { blockContentType } from './deserialize/helpers';\nimport { PortableTextObject, PortableTextTextBlock, TypedObject } from 'sanity';\nimport { detachGTData } from './data';\nimport type { CustomDeserializers } from './types';\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nexport const defaultStopTypes = [\n 'reference',\n 'date',\n 'datetime',\n 'file',\n 'geopoint',\n 'image',\n 'number',\n 'crop',\n 'hotspot',\n 'boolean',\n 'url',\n 'color',\n 'code',\n];\n\nexport const defaultMarks: Record<string, PortableTextMarkComponent> = {};\n\nexport const defaultPortableTextBlockStyles: Record<\n PortableTextBlockStyle,\n PortableTextBlockComponent | undefined\n> = {\n normal: ({ value, children }) => `<p id=\"${value._key}\">${children}</p>`,\n blockquote: ({ value, children }) =>\n `<blockquote id=\"${value._key}\">${children}</blockquote>`,\n h1: ({ value, children }) => `<h1 id=\"${value._key}\">${children}</h1>`,\n h2: ({ value, children }) => `<h2 id=\"${value._key}\">${children}</h2>`,\n h3: ({ value, children }) => `<h3 id=\"${value._key}\">${children}</h3>`,\n h4: ({ value, children }) => `<h4 id=\"${value._key}\">${children}</h4>`,\n h5: ({ value, children }) => `<h5 id=\"${value._key}\">${children}</h5>`,\n h6: ({ value, children }) => `<h6 id=\"${value._key}\">${children}</h6>`,\n};\n\nconst defaultLists: Record<'number' | 'bullet', PortableTextListComponent> = {\n number: ({ value, children }) =>\n `<ol id=\"${value._key.replace('-parent', '')}\">${children}</ol>`,\n bullet: ({ value, children }) =>\n `<ul id=\"${value._key.replace('-parent', '')}\">${children}</ul>`,\n};\n\nconst defaultListItem: PortableTextListItemComponent = ({\n value,\n children,\n}) => {\n const { _key, level } = value;\n return `<li id=\"${(_key || '').replace('-parent', '')}\" data-level=\"${level}\">${children}</li>`;\n};\n\nconst unknownBlockFunc: PortableTextBlockComponent = ({ value, children }) =>\n `<p id=\"${value._key}\" data-type=\"unknown-block-style\" data-style=\"${value.style}\">${children}</p>`;\n\nexport const customSerializers: Partial<PortableTextHtmlComponents> = {\n unknownType: ({ value }) => `<div class=\"${value._type}\"></div>`,\n types: {},\n marks: defaultMarks,\n block: defaultPortableTextBlockStyles,\n list: defaultLists,\n listItem: defaultListItem,\n unknownBlockStyle: unknownBlockFunc,\n};\n\nexport const customDeserializers: CustomDeserializers = { types: {} };\n\nexport const customBlockDeserializers: Array<unknown> = [\n // handle marks with data-gt-internal\n {\n deserialize(\n node: Node,\n next: (\n elements: Node | Node[] | NodeList\n ) => TypedObject | TypedObject[] | undefined\n ): PortableTextTextBlock | TypedObject | undefined {\n if (node.nodeType !== 1) {\n return undefined;\n }\n const el = node as HTMLElement;\n if (!el.hasChildNodes()) {\n return undefined;\n }\n\n if (!el.getAttribute('data-gt-internal')) {\n return undefined;\n }\n\n const { html, data } = detachGTData(el.outerHTML);\n const block = htmlToBlocks(html, blockContentType)[0];\n\n const children = next(el.childNodes);\n\n let markDefs: PortableTextObject[] = [];\n if ('markDefs' in block) {\n markDefs = (block.markDefs as PortableTextObject[]) ?? [];\n }\n if (data?.markDef) {\n markDefs.push(data.markDef as PortableTextObject);\n }\n if (Array.isArray(children)) {\n children.forEach((child) => {\n if (!isRecord(child)) {\n return;\n }\n const marks = Array.isArray(child.marks) ? child.marks : [];\n child.marks = data?.markDef?._key\n ? [...marks, data.markDef._key]\n : marks;\n });\n }\n // Resolve marks in the child nodes\n const output = {\n ...block,\n markDefs,\n children,\n };\n return output;\n },\n },\n //handle undeclared styles\n {\n deserialize(\n node: Node,\n next: (\n elements: Node | Node[] | NodeList\n ) => TypedObject | TypedObject[] | undefined\n ): PortableTextTextBlock | TypedObject | undefined {\n if (node.nodeType !== 1) {\n return undefined;\n }\n const el = node as HTMLElement;\n if (!el.hasChildNodes()) {\n return undefined;\n }\n\n if (el.getAttribute('data-type') !== 'unknown-block-style') {\n return undefined;\n }\n\n const style = el.getAttribute('data-style') ?? '';\n const block = htmlToBlocks(el.outerHTML, blockContentType)[0];\n\n return {\n ...block,\n style,\n children: next(el.childNodes),\n };\n },\n },\n //handle list items\n {\n deserialize(\n node: Node,\n next: (\n elements: Node | Node[] | NodeList\n ) => TypedObject | TypedObject[] | undefined\n ): PortableTextTextBlock | TypedObject | undefined {\n if (node.nodeType !== 1) {\n return undefined;\n }\n const el = node as HTMLElement;\n if (!el.hasChildNodes()) {\n return undefined;\n }\n\n if (el.tagName.toLowerCase() !== 'li') {\n return undefined;\n }\n\n const tagsToStyle: Record<string, string> = {\n ul: 'bullet',\n ol: 'number',\n };\n\n const parent = el.parentNode as HTMLUListElement | HTMLOListElement;\n if (!parent || !parent.tagName) {\n return undefined;\n }\n\n const listItem = tagsToStyle[parent.tagName.toLowerCase()];\n if (!listItem) {\n return undefined;\n }\n\n const level =\n el.getAttribute('data-level') &&\n parseInt(el.getAttribute('data-level') || '0', 10);\n const _key = el.id;\n let block = htmlToBlocks(parent.outerHTML, blockContentType)[0];\n const customStyle = el.children?.[0]?.getAttribute('data-style');\n\n //check if the object inside is also serialized -- that means it has a style\n //or custom annotation and we should use childNode serialization\n const regex = new RegExp(/<(\"[^\"]*\"|'[^']*'|[^'\">])*>/);\n if (regex.test(el.innerHTML)) {\n const newBlock = htmlToBlocks(el.innerHTML, blockContentType)[0];\n if (newBlock) {\n block = {\n ...block,\n ...newBlock,\n // @ts-ignore\n style: customStyle ?? (newBlock as PortableTextTextBlock).style,\n };\n\n //next(childNodes) plays poorly with custom styles, issue to be filed.\n if (customStyle) {\n return block as PortableTextTextBlock;\n }\n }\n }\n\n return {\n ...block,\n level,\n _key,\n listItem,\n children: next(el.childNodes),\n };\n },\n },\n];\n","import { PortableTextTextBlock } from 'sanity';\n\n// Helper function to merge multiple blocks\n// Prioritize blocks[0]\nexport function mergeBlocks(blocks: PortableTextTextBlock[]) {\n const mergedBlock = { ...blocks[0] };\n mergedBlock.markDefs = mergedBlock.markDefs ?? [];\n for (const [idx, block] of blocks.entries()) {\n if (idx === 0) {\n continue;\n }\n mergedBlock.children.push(...block.children);\n mergedBlock.markDefs.push(...(block.markDefs ?? []));\n }\n mergedBlock._type = 'block';\n\n return mergedBlock;\n}\n","// Adapted from https://github.com/sanity-io/sanity-naive-html-serializer\nimport { htmlToBlocks } from '@portabletext/block-tools';\nimport {\n customDeserializers,\n customBlockDeserializers,\n} from '../BaseSerializationConfig';\nimport { CustomDeserializers, Deserializer } from '../types';\nimport { blockContentType, preprocess } from './helpers';\nimport { mergeBlocks } from '../helpers';\n\nexport const deserializeArray = (\n arrayHTML: Element,\n deserializers: CustomDeserializers = customDeserializers,\n blockDeserializers: Array<unknown> = customBlockDeserializers\n) => {\n const output: unknown[] = [];\n const children = Array.from(arrayHTML.children);\n children.forEach((child) => {\n let deserializedObject: unknown;\n try {\n if (child.tagName?.toLowerCase() === 'span') {\n deserializedObject = preprocess(child.innerHTML);\n }\n //has specific class name or data type, so it's an obj\n else if (\n child.className ||\n child.getAttribute('data-type') === 'object'\n ) {\n deserializedObject = deserializeObject(\n child,\n deserializers,\n blockDeserializers\n );\n if (\n deserializedObject &&\n typeof deserializedObject === 'object' &&\n !Array.isArray(deserializedObject)\n ) {\n (deserializedObject as Record<string, unknown>)._key = child.id;\n }\n } else {\n const blocks = htmlToBlocks(child.outerHTML, blockContentType, {\n rules: blockDeserializers as NonNullable<\n Parameters<typeof htmlToBlocks>[2]\n >['rules'],\n });\n deserializedObject = mergeBlocks(\n blocks as unknown as Parameters<typeof mergeBlocks>[0]\n );\n (deserializedObject as Record<string, unknown>)._key = child.id;\n }\n } catch (e) {\n //eslint-disable-next-line no-console\n console.debug(\n `Tried to deserialize block: ${child.outerHTML} in an array but failed to identify it! Error: ${e}`\n );\n }\n output.push(deserializedObject);\n });\n return output;\n};\n\nexport const deserializeObject = (\n objectHTML: Element,\n deserializers: CustomDeserializers = customDeserializers,\n blockDeserializers: Array<unknown> = customBlockDeserializers\n) => {\n const deserialize = deserializers.types?.[objectHTML.className];\n if (deserialize) {\n return deserialize(objectHTML as HTMLElement);\n }\n\n const output: Record<string, unknown> = {};\n //account for anonymous inline objects\n if (objectHTML.className) {\n output._type = objectHTML.className;\n }\n const children = Array.from(objectHTML.children);\n\n children.forEach((child) => {\n //string field\n if (child.tagName?.toLowerCase() === 'span') {\n output[child.className] = preprocess(child.innerHTML);\n }\n //richer field, either object or array\n else if (child.getAttribute('data-level') === 'field') {\n const deserialized = deserializeHTML(\n child.outerHTML,\n deserializers,\n blockDeserializers\n );\n if (deserialized && Object.keys(deserialized).length) {\n output[child.className] = deserialized;\n } else {\n //eslint-disable-next-line no-console\n console.debug(\n `Deserializer: Skipping empty or unreadable HTML: ${child.outerHTML}`\n );\n }\n } else if (child.getAttribute('data-type') === 'array') {\n output[child.className] = deserializeArray(\n child,\n deserializers,\n blockDeserializers\n );\n }\n });\n return output;\n};\n\nexport const deserializeHTML = (\n html: string,\n deserializers: CustomDeserializers,\n blockDeserializers: Array<unknown>\n): Record<string, unknown> | unknown[] => {\n //parent node is always div with classname of field -- get its child\n let HTMLnode = new DOMParser().parseFromString(html, 'text/html').body\n .children[0];\n\n //catch embedded object as a field\n if (HTMLnode?.getAttribute('data-level') === 'field') {\n HTMLnode = HTMLnode.children[0];\n }\n\n if (!HTMLnode) {\n return {};\n }\n\n let output: Record<string, unknown> | unknown[];\n\n //prioritize custom deserialization\n const deserialize = deserializers.types?.[HTMLnode.className];\n if (deserialize) {\n output = deserialize(HTMLnode as HTMLElement);\n } else if (HTMLnode.getAttribute('data-type') === 'object') {\n output = deserializeObject(HTMLnode, deserializers, blockDeserializers);\n } else if (HTMLnode.getAttribute('data-type') === 'array') {\n output = deserializeArray(HTMLnode, deserializers, blockDeserializers);\n } else {\n output = {};\n //eslint-disable-next-line no-console\n console.debug(\n `Tried to deserialize block ${HTMLnode.outerHTML} but failed to identify it!`\n );\n }\n\n return output;\n};\n\nexport const deserializeDocument = <\n TDocument extends Record<string, unknown> = Record<string, unknown>,\n>(\n serializedDoc: string,\n deserializers: CustomDeserializers = customDeserializers,\n blockDeserializers: Array<unknown> = customBlockDeserializers\n): TDocument => {\n const metadata: Record<string, unknown> = {};\n const head = new DOMParser().parseFromString(serializedDoc, 'text/html').head;\n\n Array.from(head.children).forEach((metaTag) => {\n const validTags = ['_id', '_rev', '_type'];\n const metaName = metaTag.getAttribute('name');\n if (metaName && validTags.includes(metaName)) {\n metadata[metaName] = metaTag.getAttribute('content');\n }\n });\n\n const content = deserializeHTML(\n serializedDoc,\n deserializers,\n blockDeserializers\n ) as Record<string, unknown>;\n\n return {\n ...content,\n ...metadata,\n } as TDocument;\n};\n\nexport const BaseDocumentDeserializer: Deserializer = {\n deserializeDocument,\n deserializeHTML,\n};\n","// Adapted from https://github.com/sanity-io/sanity-naive-html-serializer\n\nimport { ObjectField, TypedObject } from 'sanity';\n\nconst META_FIELDS = ['_key', '_type', '_id'];\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/*\n * Helper. If field-level translation pattern used, only sends over\n * content from the base language. Works recursively, so if users\n * use this pattern several layers deep, base language fields will still be found.\n */\nexport const languageObjectFieldFilter = (\n obj: Record<string, unknown>,\n baseLang: string\n): Record<string, unknown> => {\n const filterToLangField = (childObj: Record<string, unknown>) => {\n const filteredObj: Record<string, unknown> = {};\n filteredObj[baseLang] = childObj[baseLang];\n META_FIELDS.forEach((field) => {\n if (childObj[field]) {\n filteredObj[field] = childObj[field];\n }\n });\n return filteredObj;\n };\n\n const findBaseLang = (\n childObj: Record<string, unknown>\n ): Record<string, unknown> => {\n const filteredObj: Record<string, unknown> = {};\n META_FIELDS.forEach((field) => {\n if (childObj[field]) {\n filteredObj[field] = childObj[field];\n }\n });\n\n for (const key in childObj) {\n if (childObj.hasOwnProperty(key)) {\n const value: unknown = childObj[key];\n //we've reached a base language field, add it to\n //what we want to send to translation\n if (isRecord(value) && Object.hasOwn(value, baseLang)) {\n filteredObj[key] = filterToLangField(value);\n }\n //we have an array that may have language fields in its objects\n else if (\n Array.isArray(value) &&\n value.length &&\n typeof value[0] === 'object'\n ) {\n //recursively find and filter for any objects that have the base language\n const validLangObjects = value.reduce<Record<string, unknown>[]>(\n (validArr, objInArray) => {\n if (!isRecord(objInArray)) {\n return validArr;\n }\n if (objInArray._type === 'block') {\n validArr.push(objInArray);\n } else if (Object.hasOwn(objInArray, baseLang)) {\n validArr.push(filterToLangField(objInArray));\n } else {\n const filtered = findBaseLang(objInArray);\n const nonMetaFields = Object.keys(filtered).filter(\n (objInArrayKey) => META_FIELDS.indexOf(objInArrayKey) === -1\n );\n if (nonMetaFields.length) {\n validArr.push(filtered);\n }\n }\n return validArr;\n },\n []\n );\n if (validLangObjects.length) {\n filteredObj[key] = validLangObjects;\n }\n }\n //we have an object nested in an object\n //recurse down the tree\n else if (isRecord(value)) {\n const nestedLangObj = findBaseLang(value);\n const nonMetaFields = Object.keys(nestedLangObj).filter(\n (nestedObjKey) => META_FIELDS.indexOf(nestedObjKey) === -1\n );\n if (nonMetaFields.length) {\n filteredObj[key] = nestedLangObj;\n }\n }\n }\n }\n return filteredObj;\n };\n\n //send top level object into recursive function\n return findBaseLang(obj);\n};\n\n/**\n * Schema `options` namespaces that can exclude a field from translation.\n * `gt.exclude` is gt-sanity's own; `documentInternationalization.exclude`\n * (@sanity/document-internationalization) and `aiAssist.exclude`\n * (@sanity/assist) are honored so studios don't have to maintain a second\n * exclusion pattern for GT.\n */\ntype FieldExclusionOptions = {\n gt?: { exclude?: boolean };\n documentInternationalization?: { exclude?: boolean };\n aiAssist?: { exclude?: boolean };\n};\n\nexport const isFieldExcludedByOptions = (options: unknown): boolean => {\n if (!isRecord(options)) return false;\n const exclusionOptions = options as FieldExclusionOptions;\n return (\n exclusionOptions.gt?.exclude === true ||\n exclusionOptions.documentInternationalization?.exclude === true ||\n exclusionOptions.aiAssist?.exclude === true\n );\n};\n\n/** Resolves a schema type name to its raw type definition, if registered. */\nexport type SchemaTypeResolver = (\n typeName: string\n) => { type?: unknown; options?: unknown } | undefined;\n\nconst getFieldTypeName = (field: ObjectField): string | undefined => {\n const fieldType = (\n field as ObjectField & { type?: string | { name?: string } }\n ).type;\n return typeof fieldType === 'string' ? fieldType : fieldType?.name;\n};\n\n/**\n * Exclusion options on a type definition apply to every value of that type,\n * including through chains of type aliases. Walks the named type and each\n * alias target until a definition is excluded or the chain ends.\n */\nexport const isTypeExcludedByOptions = (\n typeName: string | undefined,\n resolveType: SchemaTypeResolver | undefined\n): boolean => {\n if (!resolveType) return false;\n const seen = new Set<string>();\n let current = typeName;\n while (current && !seen.has(current)) {\n seen.add(current);\n const typeDef = resolveType(current);\n if (!typeDef) return false;\n if (isFieldExcludedByOptions(typeDef.options)) return true;\n current = typeof typeDef.type === 'string' ? typeDef.type : undefined;\n }\n return false;\n};\n\n/**\n * A schema field is excluded from translation by the legacy `localize: false`\n * field property, by one of the `options` namespaces on the field itself, or\n * by exclusion options on the type definition the field references.\n */\nexport const isFieldExcludedFromTranslation = (\n field: ObjectField,\n resolveType?: SchemaTypeResolver\n): boolean => {\n const fieldMetadata = field as ObjectField & {\n localize?: boolean;\n options?: unknown;\n };\n return (\n fieldMetadata.localize === false ||\n isFieldExcludedByOptions(fieldMetadata.options) ||\n isTypeExcludedByOptions(getFieldTypeName(field), resolveType)\n );\n};\n\n/*\n * Eliminates stop-types and non-localizable fields\n * for document-level translation.\n */\nexport const fieldFilter = (\n obj: Record<string, unknown>,\n objFields: ObjectField[],\n stopTypes: string[],\n resolveType?: SchemaTypeResolver\n): TypedObject => {\n const filteredObj: TypedObject = {\n _type: typeof obj._type === 'string' ? obj._type : '',\n };\n\n const fieldFilterFunc = (field: ObjectField): boolean => {\n const fieldType = getFieldTypeName(field);\n\n if (isFieldExcludedFromTranslation(field, resolveType)) {\n return false;\n } else if (fieldType === 'string' || fieldType === 'text') {\n return true;\n } else if (Array.isArray(obj[field.name])) {\n return true;\n } else if (fieldType && !stopTypes.includes(fieldType)) {\n return true;\n }\n return false;\n };\n\n const validFields = [\n ...META_FIELDS,\n ...objFields.filter(fieldFilterFunc).map((field) => field.name),\n ];\n validFields.forEach((field) => {\n if (obj[field]) {\n filteredObj[field] = obj[field];\n }\n });\n return filteredObj;\n};\n","// Adapted from https://github.com/sanity-io/sanity-naive-html-serializer\n\nimport {\n defaultStopTypes,\n customSerializers,\n} from '../BaseSerializationConfig';\nimport { ObjectField, SanityDocument, TypedObject, Schema } from 'sanity';\nimport { TranslationLevel } from '../types';\nimport {\n fieldFilter,\n isFieldExcludedFromTranslation,\n isTypeExcludedByOptions,\n languageObjectFieldFilter,\n} from './fieldFilters';\nimport {\n PortableTextHtmlComponents,\n PortableTextTypeComponent,\n toHTML,\n} from '@portabletext/to-html';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\n\nconst META_FIELDS = ['_key', '_type', '_id', '_weak'];\n\ntype SchemaTypeWithFields = {\n type?: unknown;\n fields?: ObjectField[];\n options?: unknown;\n};\n\n/**\n * A raw (uncompiled) schema field or array-member definition. Inline object\n * declarations carry their `fields` here, and array declarations carry their\n * member definitions in `of`.\n */\ntype RawFieldDef = {\n name?: string;\n type?: string;\n fields?: ObjectField[];\n of?: RawFieldDef[];\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nexport const BaseDocumentSerializer = (schemas: Schema) => {\n /*\n * Helper function that allows us to get metadata (like `localize: false`) from schema fields.\n */\n const getSchema = (name: string): SchemaTypeWithFields | undefined =>\n schemas?._original?.types.find((s) => s.name === name) as\n | SchemaTypeWithFields\n | undefined;\n\n /*\n * Resolve a type name to its declared fields, following chains of type\n * aliases (a type whose definition just references another named type).\n */\n const resolveSchemaFields = (\n typeName: string | undefined\n ): ObjectField[] | undefined => {\n const seen = new Set<string>();\n let current = typeName;\n while (current && !seen.has(current)) {\n seen.add(current);\n const typeDef = getSchema(current);\n if (!typeDef) return undefined;\n if (typeDef.fields) return typeDef.fields;\n current = typeof typeDef.type === 'string' ? typeDef.type : undefined;\n }\n return undefined;\n };\n\n const serializeObject = (\n obj: TypedObject,\n stopTypes: string[],\n serializers: Partial<PortableTextHtmlComponents>,\n // Declared fields from the enclosing field or array-member definition.\n // Used when the value itself resolves to no schema type β€” anonymous\n // inline objects carry no `_type`.\n declaredFields?: ObjectField[]\n ) => {\n if (stopTypes.includes(obj._type)) {\n return '';\n }\n\n // The exclusion options also apply to a type definition's own `options`\n // (\"this field or type\" in the native plugins' semantics), including\n // through chains of type aliases.\n if (isTypeExcludedByOptions(obj._type, getSchema)) {\n return '';\n }\n\n //if user has declared a custom serializer, use that\n //instead of this method\n const typeSerializers = isRecord(serializers.types)\n ? serializers.types\n : ({} as PortableTextHtmlComponents['types']);\n const hasSerializer = Object.keys(typeSerializers).includes(obj._type);\n if (hasSerializer) {\n return toHTML([obj], { components: serializers });\n }\n\n //we don't need to worry about PT types\n if (obj._type === 'span' || obj._type === 'block') {\n return toHTML(obj, { components: serializers });\n }\n\n //if schema is available, encode values in the order they're declared in the schema,\n //since this will likely be more intuitive for a translator.\n //fields the schema excludes from translation (localize: false or an\n //options exclusion) are dropped here so exclusion applies at any depth.\n let fieldNames = Object.keys(obj).filter((key) => key !== '_type');\n const resolvedFields = resolveSchemaFields(obj._type);\n if (resolvedFields) {\n fieldNames = resolvedFields\n .filter((field) => !isFieldExcludedFromTranslation(field, getSchema))\n .map((field) => field.name)\n .filter((schemaKey) => Object.keys(obj).includes(schemaKey));\n } else if (declaredFields) {\n //anonymous inline objects have no schema type of their own; keep every\n //runtime key (undeclared data still round-trips) but drop keys whose\n //inline declaration excludes them from translation\n const excludedNames = new Set(\n declaredFields\n .filter((field) => isFieldExcludedFromTranslation(field, getSchema))\n .map((field) => field.name)\n );\n fieldNames = fieldNames.filter((name) => !excludedNames.has(name));\n }\n const knownFields = resolvedFields ?? declaredFields;\n\n //account for anonymous inline objects\n if (typeof obj === 'object' && !obj._type) {\n obj._type = '';\n }\n\n //in some cases, we might recurse through many objects of the same type\n //we should take all methods necessary to ensure state does not persist\n //otherwise we risk using old serialization methods on new items\n const newSerializationMethods: Record<string, PortableTextTypeComponent> =\n {};\n const tempType = `${obj._type}__temp_type__${Math.random().toString(36).substring(7)}`;\n const objToSerialize: TypedObject = { _type: tempType };\n //for our default serialization method, we only need to\n //capture metadata. the rest will be recursively turned into strings.\n META_FIELDS.filter((f) => f !== '_type').forEach((field) => {\n objToSerialize[field] = obj[field];\n });\n\n let innerHTML = '';\n\n //if it's a custom object, iterate through its keys to find and serialize translatable content\n fieldNames.forEach((fieldName) => {\n let htmlField = '';\n\n if (!META_FIELDS.includes(fieldName)) {\n const value = obj[fieldName];\n const fieldDef = knownFields?.find(\n (field) => field.name === fieldName\n ) as RawFieldDef | undefined;\n //strings are either string fields or have recursively been turned\n //into HTML because they were a nested object or array\n if (typeof value === 'string') {\n const htmlRegex = new RegExp(/<(\"[^\"]*\"|'[^']*'|[^'\">])*>/);\n if (htmlRegex.test(value)) {\n htmlField = value;\n } else {\n htmlField = `<span class=\"${fieldName}\">${value}</span>`;\n }\n }\n\n //array fields get filtered and its children serialized\n else if (Array.isArray(value)) {\n htmlField = serializeArray(\n value,\n fieldName,\n stopTypes,\n {\n ...serializers,\n types: { ...typeSerializers },\n },\n fieldDef?.of\n );\n }\n\n //this is an object in an object, serialize it first\n else if (isRecord(value)) {\n const embeddedObject = value as TypedObject;\n const embeddedFields = resolveSchemaFields(embeddedObject._type);\n let toTranslate = embeddedObject;\n if (embeddedFields) {\n toTranslate = fieldFilter(\n toTranslate,\n embeddedFields,\n stopTypes,\n getSchema\n );\n }\n const objHTML = serializeObject(\n toTranslate,\n stopTypes,\n {\n ...serializers,\n types: { ...typeSerializers },\n },\n fieldDef?.fields\n );\n htmlField = `<div class=\"${fieldName}\" data-level=\"field\">${objHTML}</div>`;\n }\n\n innerHTML += htmlField;\n }\n });\n\n if (!innerHTML) {\n return '';\n }\n\n newSerializationMethods[tempType] = ({ value }: { value: TypedObject }) => {\n let div = `<div class=\"${value._type.split('__temp_type__')[0]}\"`;\n if (value._key || value._id) {\n div += `id=\"${value._key ?? value._id}\"`;\n }\n\n return [div, ` data-type=\"object\">${innerHTML}</div>`].join('');\n };\n\n let serializedBlock = '';\n try {\n serializedBlock = toHTML(objToSerialize, {\n components: {\n ...serializers,\n types: {\n ...typeSerializers,\n ...newSerializationMethods,\n },\n },\n });\n } catch (err) {\n //eslint-disable-next-line no-console -- this is a warning\n console.warn(\n `Had issues serializing block of type \"${obj._type}\". Specify a serialization method for this block in your serialization config. Received error: ${err}`\n );\n }\n\n return serializedBlock;\n };\n\n const serializeArray = (\n fieldContent: Array<Record<string, unknown> | string>,\n fieldName: string,\n stopTypes: string[],\n serializers: Partial<PortableTextHtmlComponents>,\n // Declared member definitions (the array field's `of`), used to resolve\n // fields of anonymous inline object members that carry no schema type.\n memberDefs?: RawFieldDef[]\n ) => {\n //filter for any blocks that user has indicated\n //should not be sent for translation\n const validBlocks = fieldContent.filter(\n (block) =>\n typeof block === 'string' ||\n typeof block._type !== 'string' ||\n !stopTypes.includes(block._type)\n );\n\n //fields declared inline on the matching array-member definition\n const declaredMemberFields = (\n blockType: string | undefined\n ): ObjectField[] | undefined => {\n if (!memberDefs?.length) return undefined;\n const byName = memberDefs.find(\n (def) => def.name === blockType || def.type === blockType\n );\n if (byName?.fields) return byName.fields;\n if (!blockType && memberDefs.length === 1) return memberDefs[0].fields;\n return undefined;\n };\n\n const output = validBlocks.map((block) => {\n //if object in array is just a string, just return it\n if (typeof block === 'string') {\n return `<span>${block}</span>`;\n }\n //take out any fields in this block that should\n //not be sent to translation\n const blockType =\n typeof block._type === 'string' ? block._type : undefined;\n const memberFields = resolveSchemaFields(blockType);\n const filtered = memberFields\n ? fieldFilter(block, memberFields, stopTypes, getSchema)\n : block;\n //send to serialization method\n return serializeObject(\n filtered as TypedObject,\n stopTypes,\n serializers,\n declaredMemberFields(blockType)\n );\n });\n\n //encode this with data-level field\n return `<div class=\"${fieldName}\" data-type=\"array\">${output.join('')}</div>`;\n };\n\n /*\n * Main parent function: finds fields to translate, and feeds them to appropriate child serialization\n * methods.\n */\n const serializeDocument = (\n doc: SanityDocument,\n translationLevel: TranslationLevel = 'document',\n baseLang: string = libraryDefaultLocale,\n stopTypes = defaultStopTypes,\n serializers = customSerializers\n ) => {\n const schema = getSchema(doc._type);\n let filteredObj: Record<string, unknown> = {};\n\n //field level translations explicitly send over any fields that\n //match the base language, regardless of depth\n if (translationLevel === 'field') {\n filteredObj = languageObjectFieldFilter(doc, baseLang);\n }\n //otherwise, we can refer to the schema and a list of stop types\n //to determine what should not be sent\n else {\n filteredObj = fieldFilter(\n doc,\n schema?.fields ?? [],\n stopTypes,\n getSchema\n );\n }\n\n const serializedFields: Record<string, unknown> = {};\n\n for (const key in filteredObj) {\n if (filteredObj.hasOwnProperty(key) === false) continue;\n const value = filteredObj[key];\n const fieldDef = schema?.fields?.find((field) => field.name === key) as\n | RawFieldDef\n | undefined;\n\n if (typeof value === 'string') {\n serializedFields[key] = value;\n } else if (Array.isArray(value)) {\n serializedFields[key] = serializeArray(\n value.filter(\n (item): item is Record<string, unknown> | string =>\n typeof item === 'string' || isRecord(item)\n ),\n key,\n stopTypes,\n serializers,\n fieldDef?.of\n );\n } else if (\n value &&\n isRecord(value) &&\n !stopTypes.find((stopType) => stopType == value?._type)\n ) {\n const serialized = serializeObject(\n value as TypedObject,\n stopTypes,\n serializers,\n fieldDef?.fields\n );\n serializedFields[key] =\n `<div class=\"${key}\" data-level='field'>${serialized}</div>`;\n }\n }\n\n //create a valid HTML file\n const rawHTMLBody = document.createElement('body');\n rawHTMLBody.innerHTML = serializeObject(\n serializedFields as TypedObject,\n stopTypes,\n serializers\n );\n\n const rawHTMLHead = document.createElement('head');\n const metaFields = ['_id', '_type', '_rev'];\n //save our metadata as meta tags so we can use them later on\n metaFields.forEach((field) => {\n const metaEl = document.createElement('meta');\n metaEl.setAttribute('name', field);\n metaEl.setAttribute('content', doc[field] as string);\n rawHTMLHead.appendChild(metaEl);\n });\n //encode version so we can use the correct deserialization methods\n const versionMeta = document.createElement('meta');\n versionMeta.setAttribute('name', 'version');\n versionMeta.setAttribute('content', '3');\n rawHTMLHead.appendChild(versionMeta);\n\n const rawHTML = document.createElement('html');\n rawHTML.appendChild(rawHTMLHead);\n rawHTML.appendChild(rawHTMLBody);\n\n return {\n name: doc._id,\n content: rawHTML.outerHTML,\n };\n };\n\n return {\n serializeDocument,\n fieldFilter,\n languageObjectFieldFilter,\n serializeArray,\n serializeObject,\n };\n};\n","import {\n findLocaleItem,\n isInternationalizedArrayField,\n isRecord,\n} from './detect';\n\n/**\n * Collapse every internationalized-array field in a value down to just its\n * source-locale `value`, recursing into nested objects/arrays.\n *\n * This runs *before* the generic HTML serializer so that the per-locale item\n * arrays never reach `serializeArray` (which would otherwise emit every\n * locale). After collapsing, an `internationalizedArrayString` field is a plain\n * string, an `internationalizedArrayText` is a plain string, Portable Text is a\n * plain `block` array, and a custom value object is a plain object β€” all shapes\n * the existing document-level serializer already round-trips.\n *\n * Returns `undefined` when a field has no source-locale entry, so the caller\n * drops it (nothing to translate) rather than emitting an empty field.\n */\nexport function collapseToSourceLocale(\n value: unknown,\n sourceLocale: string\n): unknown {\n if (isInternationalizedArrayField(value)) {\n const sourceItem = findLocaleItem(value, sourceLocale);\n if (!sourceItem) {\n return undefined;\n }\n // Recurse: the source value may itself contain nested localized fields.\n return collapseToSourceLocale(sourceItem.value, sourceLocale);\n }\n\n if (Array.isArray(value)) {\n return value\n .map((item) => collapseToSourceLocale(item, sourceLocale))\n .filter((item) => item !== undefined);\n }\n\n if (isRecord(value)) {\n const collapsed: Record<string, unknown> = {};\n for (const key of Object.keys(value)) {\n const collapsedValue = collapseToSourceLocale(value[key], sourceLocale);\n if (collapsedValue !== undefined) {\n collapsed[key] = collapsedValue;\n }\n }\n return collapsed;\n }\n\n return value;\n}\n","import { SanityDocument, Schema } from 'sanity';\nimport { BaseDocumentDeserializer } from '../serialization/deserialize/BaseDocumentDeserializer';\nimport { BaseDocumentSerializer } from '../serialization/serialize/index';\nimport {\n defaultStopTypes,\n customSerializers,\n customBlockDeserializers,\n} from '../serialization/BaseSerializationConfig';\nimport { PortableTextHtmlComponents } from '@portabletext/to-html';\nimport { pluginConfig } from '../adapter/core';\nimport merge from 'lodash.merge';\nimport { deleteMatchingFields } from './applyDocuments';\nimport type { FieldMatcher } from '../adapter/types';\nimport { getPublishedId } from './documentIds';\nimport type {\n CustomDeserializers,\n TranslationLevel,\n} from '../serialization/types';\nimport { collapseToSourceLocale } from '../serialization/internationalizedArray/collapse';\n\nexport function deserializeDocument(document: string) {\n const deserializers = merge(\n { types: {} },\n pluginConfig.getAdditionalDeserializers()\n ) as CustomDeserializers;\n const blockDeserializers = [\n ...customBlockDeserializers,\n ...pluginConfig.getAdditionalBlockDeserializers(),\n ];\n const deserialized = BaseDocumentDeserializer.deserializeDocument(\n document,\n deserializers,\n blockDeserializers\n ) as SanityDocument;\n return deserialized;\n}\n\nexport function serializeDocument(\n document: SanityDocument,\n schema: Schema,\n baseLanguage: string,\n level: TranslationLevel = 'document'\n) {\n const stopTypes = [\n ...defaultStopTypes,\n ...pluginConfig.getAdditionalStopTypes(),\n ];\n const serializers = merge(\n customSerializers,\n pluginConfig.getAdditionalSerializers()\n ) satisfies Partial<PortableTextHtmlComponents>;\n\n let docToSerialize = stripIgnoredFields(\n document,\n pluginConfig.getIgnoreFields(),\n pluginConfig.getDedupeFields()\n );\n\n // The internationalized-array model collapses each localized field down to\n // its source-locale value, then serializes through the standard document\n // path so the existing HTML format and deserializer are reused as-is.\n let innerLevel: TranslationLevel = level;\n if (level === 'internationalizedArray') {\n docToSerialize = collapseToSourceLocale(\n docToSerialize,\n baseLanguage\n ) as SanityDocument;\n innerLevel = 'document';\n }\n\n const serialized = BaseDocumentSerializer(schema).serializeDocument(\n docToSerialize,\n innerLevel,\n baseLanguage,\n stopTypes,\n serializers\n );\n return serialized;\n}\n\nfunction stripIgnoredFields(\n document: SanityDocument,\n ignoreFields: FieldMatcher[],\n dedupeFields: FieldMatcher[]\n): SanityDocument {\n const fieldsToStrip = [...ignoreFields, ...dedupeFields];\n if (fieldsToStrip.length === 0) return document;\n\n const strippedDoc = JSON.parse(JSON.stringify(document)) as SanityDocument;\n\n deleteMatchingFields(\n getPublishedId(document._id),\n strippedDoc,\n fieldsToStrip\n );\n\n return strippedDoc;\n}\n","import { SanityClient, SanityDocument, Schema } from 'sanity';\nimport { pluginConfig } from '../adapter/core';\nimport { documentLevelPatch } from '../configuration/baseDocumentLevelConfig/documentLevelPatch';\nimport { internationalizedArrayPatch } from '../configuration/internationalizedArrayConfig/internationalizedArrayPatch';\nimport type {\n SerializedDocument,\n TranslationLevel,\n} from '../serialization/types';\nimport type { GTFile } from '../types';\nimport { serializeDocument } from '../utils/serialize';\n\n/**\n * A translation strategy bundles the serialize/patch pair for a given level.\n * The shared GT upload/enqueue/status/download workflow is identical across\n * strategies; only how a document is turned into the GT HTML file and how the\n * translated file is written back to Sanity differs.\n */\nexport type SanityTranslationAdapter = {\n level: TranslationLevel;\n serialize: (\n document: SanityDocument,\n schema: Schema,\n baseLanguage: string\n ) => SerializedDocument;\n patch: (\n docInfo: GTFile,\n deserialized: SanityDocument,\n localeId: string,\n client: SanityClient,\n mergeWithTargetLocale?: boolean\n ) => Promise<void>;\n};\n\nconst documentAdapter: SanityTranslationAdapter = {\n level: 'document',\n serialize: (document, schema, baseLanguage) =>\n serializeDocument(document, schema, baseLanguage, 'document'),\n patch: (docInfo, deserialized, localeId, client, mergeWithTargetLocale) =>\n documentLevelPatch(\n docInfo,\n deserialized,\n localeId,\n client,\n pluginConfig.getLanguageField(),\n mergeWithTargetLocale\n ),\n};\n\nconst internationalizedArrayAdapter: SanityTranslationAdapter = {\n level: 'internationalizedArray',\n serialize: (document, schema, baseLanguage) =>\n serializeDocument(document, schema, baseLanguage, 'internationalizedArray'),\n patch: (docInfo, deserialized, localeId, client) =>\n internationalizedArrayPatch(docInfo, deserialized, localeId, client),\n};\n\nfunction matchesFieldLevel(type: string | undefined): boolean {\n if (!type) {\n return false;\n }\n return pluginConfig\n .getFieldLevelDocuments()\n .some((filter) => filter.type === type);\n}\n\n/**\n * Resolve which strategy a document type uses:\n * - `document` β†’ always document-level (default; unchanged).\n * - `internationalizedArray` β†’ always the array strategy.\n * - `mixed` β†’ array strategy for `fieldLevelDocuments`, else\n * document-level.\n */\nexport function getTranslationStrategyForType(\n type: string | undefined\n): SanityTranslationAdapter {\n const level = pluginConfig.getTranslationLevel();\n if (level === 'internationalizedArray') {\n return internationalizedArrayAdapter;\n }\n if (level === 'mixed') {\n return matchesFieldLevel(type)\n ? internationalizedArrayAdapter\n : documentAdapter;\n }\n return documentAdapter;\n}\n\nexport function getTranslationStrategy(\n document: SanityDocument\n): SanityTranslationAdapter {\n return getTranslationStrategyForType(document._type);\n}\n","import type { GTFile, Secrets } from '../types';\nimport { gt, overrideConfig } from '../adapter/core';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport type { SerializedDocument } from '../serialization/types';\n\n// note: this function is used to create a new translation task\n// uploads files & calls the getTranslationTask function\nexport async function uploadFiles(\n documents: {\n info: GTFile;\n serializedDocument: SerializedDocument;\n }[],\n secrets: Secrets | null\n): Promise<Awaited<ReturnType<typeof gt.uploadSourceFiles>>> {\n overrideConfig(secrets);\n const uploadResult = await gt.uploadSourceFiles(\n documents.map(({ info, serializedDocument }) => ({\n source: {\n content: serializedDocument.content,\n fileName: `sanity/${info.documentId}`,\n fileId: info.documentId,\n fileFormat: 'HTML',\n locale: gt.sourceLocale || libraryDefaultLocale,\n versionId: info.versionId || undefined,\n },\n })),\n {\n sourceLocale: gt.sourceLocale || libraryDefaultLocale,\n }\n );\n return uploadResult;\n}\n","import { gt, overrideConfig, pluginConfig } from '../adapter/core';\nimport type { Secrets } from '../types';\n\nexport async function initProject(\n uploadResult: Awaited<ReturnType<typeof gt.uploadSourceFiles>>,\n options: { timeout?: number },\n secrets: Secrets\n): Promise<boolean> {\n overrideConfig(secrets);\n // Calculate timeout once for setup fetching\n // Accept number or numeric string, default to 600s\n const timeoutVal =\n options?.timeout !== undefined ? Number(options.timeout) : 600;\n const setupTimeoutSeconds = Number.isFinite(timeoutVal) ? timeoutVal : 600;\n\n const setupResult = await gt.setupProject(uploadResult.uploadedFiles, {\n locales: pluginConfig.getLocales(),\n });\n\n if (setupResult.status === 'queued') {\n const { complete, jobs } = await gt.awaitJobs([setupResult.setupJobId], {\n pollingIntervalSeconds: 2,\n timeoutSeconds: setupTimeoutSeconds,\n });\n const [job] = jobs;\n\n if (job?.status === 'completed') {\n // eslint-disable-next-line no-console\n console.log('Setup successfully completed');\n } else if (!complete) {\n // eslint-disable-next-line no-console\n console.log(\n 'Setup timed out β€” proceeding without setup (Timed out while waiting for setup generation)'\n );\n } else if (job?.status === 'failed') {\n // eslint-disable-next-line no-console\n console.log(\n `Setup failed β€” proceeding without setup (${job.error?.message ?? 'Unknown error'})`\n );\n } else {\n // eslint-disable-next-line no-console\n console.log('Setup status unknown β€” proceeding without setup');\n }\n }\n\n return true;\n}\n","import { libraryDefaultLocale } from 'generaltranslation/internal';\nimport { gt, overrideConfig } from '../adapter/core';\nimport type { Secrets } from '../types';\n\nexport async function createJobs(\n uploadResult: Awaited<ReturnType<typeof gt.uploadSourceFiles>>,\n localeIds: string[],\n secrets: Secrets,\n // Discard any translation GT already holds for these files and retranslate\n // from source. Without this, GT reuses unchanged content β€” including\n // translations captured from the Studio β€” so a bad translation can never be\n // regenerated.\n force: boolean = false\n): Promise<Awaited<ReturnType<typeof gt.enqueueFiles>>> {\n overrideConfig(secrets);\n const enqueueResult = await gt.enqueueFiles(uploadResult.uploadedFiles, {\n sourceLocale: gt.sourceLocale || libraryDefaultLocale,\n targetLocales: localeIds,\n force,\n });\n return enqueueResult;\n}\n","import type { SanityClient, SanityDocument } from 'sanity';\nimport { pluginConfig } from '../adapter/core';\nimport { hasLocaleContent } from '../serialization/internationalizedArray/detect';\nimport type { TranslationFunctionContext } from '../types';\nimport {\n dedupeDocumentsPreferDraft,\n getDocumentPublishedId,\n} from '../utils/documentIds';\nimport {\n metadataTranslationRef,\n metadataTranslations,\n TRANSLATION_METADATA_TYPE,\n} from '../utils/translationMetadata';\nimport { serializeDocument } from '../utils/serialize';\nimport { getTranslationStrategy } from './strategy';\n\n/**\n * A translation that already exists in Sanity (a human-edited translated\n * document or a translated internationalized-array item), serialized to the\n * same HTML format the source document is uploaded in.\n */\nexport type ExistingTranslation = {\n locale: string;\n content: string;\n};\n\ntype TranslationMetadataRow = {\n sourceDocId?: string;\n translations?: { language?: string; docId?: string }[];\n};\n\n/**\n * Collect and serialize the translations that already exist in Sanity for the\n * given source documents, keyed by the source document's published id.\n *\n * - Document-level types: the translated documents linked through\n * `translation.metadata`, preferring drafts so unpublished human edits are\n * also preserved.\n * - Internationalized-array types: the target-locale items stored in the\n * source document itself, collapsed per locale.\n *\n * Locales without existing content are omitted, so callers only upload\n * translations that a human could actually have edited.\n */\nexport async function collectExistingTranslations(\n documents: SanityDocument[],\n targetLocaleIds: string[],\n { client, schema }: TranslationFunctionContext\n): Promise<Map<string, ExistingTranslation[]>> {\n const existing = new Map<string, ExistingTranslation[]>();\n if (documents.length === 0 || targetLocaleIds.length === 0) {\n return existing;\n }\n\n const sourceLocale = pluginConfig.getSourceLocale();\n const languageField = pluginConfig.getLanguageField();\n const localeIds = targetLocaleIds.filter(\n (localeId) => localeId !== sourceLocale\n );\n if (localeIds.length === 0) {\n return existing;\n }\n\n const documentLevelDocs: SanityDocument[] = [];\n for (const doc of documents) {\n const strategy = getTranslationStrategy(doc);\n if (strategy.level !== 'internationalizedArray') {\n documentLevelDocs.push(doc);\n continue;\n }\n\n // Array-level translations live in the source document itself. Collapsing\n // to the target locale reuses the source serialization path: fields with\n // no item for that locale are dropped, so only translated content ships.\n const { [languageField]: _language, ...cleanDoc } = doc;\n const translations: ExistingTranslation[] = [];\n for (const localeId of localeIds) {\n if (!hasLocaleContent(cleanDoc, localeId)) continue;\n const serialized = serializeDocument(\n cleanDoc as SanityDocument,\n schema,\n localeId,\n 'internationalizedArray'\n );\n translations.push({ locale: localeId, content: serialized.content });\n }\n if (translations.length > 0) {\n existing.set(getDocumentPublishedId(doc), translations);\n }\n }\n\n if (documentLevelDocs.length > 0) {\n const documentLevel = await collectDocumentLevelTranslations(\n documentLevelDocs,\n localeIds,\n sourceLocale,\n languageField,\n client,\n schema\n );\n for (const [sourceDocId, translations] of documentLevel) {\n existing.set(sourceDocId, translations);\n }\n }\n\n return existing;\n}\n\nasync function collectDocumentLevelTranslations(\n documents: SanityDocument[],\n localeIds: string[],\n sourceLocale: string,\n languageField: string,\n client: SanityClient,\n schema: TranslationFunctionContext['schema']\n): Promise<Map<string, ExistingTranslation[]>> {\n const existing = new Map<string, ExistingTranslation[]>();\n const sourceDocIds = documents.map(getDocumentPublishedId);\n\n const query = `*[\n _type == '${TRANSLATION_METADATA_TYPE}' &&\n ${metadataTranslationRef('$sourceLocale')} in $sourceDocIds\n ] {\n 'sourceDocId': ${metadataTranslationRef('$sourceLocale')},\n 'translations': ${metadataTranslations('in $localeIds', 'defined(value._ref)')}{\n language,\n 'docId': value._ref\n }\n }`;\n\n const metadataRows = await client.fetch<TranslationMetadataRow[]>(query, {\n sourceLocale,\n sourceDocIds,\n localeIds,\n });\n\n // Use the last entry per locale defensively: older plugin versions could\n // create duplicate locale entries when bulk imports raced.\n const refsBySource = new Map<string, Map<string, string>>();\n for (const row of metadataRows) {\n if (!row.sourceDocId) continue;\n const localeRefs =\n refsBySource.get(row.sourceDocId) ?? new Map<string, string>();\n for (const translation of row.translations ?? []) {\n if (translation.language && translation.docId) {\n localeRefs.set(translation.language, translation.docId);\n }\n }\n refsBySource.set(row.sourceDocId, localeRefs);\n }\n\n const translatedDocIds = Array.from(\n new Set(\n Array.from(refsBySource.values()).flatMap((localeRefs) =>\n Array.from(localeRefs.values())\n )\n )\n );\n if (translatedDocIds.length === 0) {\n return existing;\n }\n\n // Fetch published and draft versions in one query, preferring drafts so\n // unpublished human edits are included.\n const translatedDocs = await client.fetch<SanityDocument[]>(\n `*[_id in $ids || _id in $draftIds]`,\n {\n ids: translatedDocIds,\n draftIds: translatedDocIds.map((id) => `drafts.${id}`),\n }\n );\n const translatedById = new Map(\n dedupeDocumentsPreferDraft(translatedDocs).map((doc) => [\n getDocumentPublishedId(doc),\n doc,\n ])\n );\n\n for (const [sourceDocId, localeRefs] of refsBySource) {\n const translations: ExistingTranslation[] = [];\n for (const [localeId, translatedDocId] of localeRefs) {\n const translatedDoc = translatedById.get(translatedDocId);\n if (!translatedDoc) continue;\n const { [languageField]: _language, ...cleanDoc } = translatedDoc;\n const serialized = serializeDocument(\n cleanDoc as SanityDocument,\n schema,\n sourceLocale,\n 'document'\n );\n translations.push({ locale: localeId, content: serialized.content });\n }\n if (translations.length > 0) {\n existing.set(sourceDocId, translations);\n }\n }\n\n return existing;\n}\n","import type { SanityDocument } from 'sanity';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport { gt, overrideConfig } from '../adapter/core';\nimport { getDocumentPublishedId } from '../utils/documentIds';\nimport { collectExistingTranslations } from './collectExistingTranslations';\n\nimport type { Secrets, TranslationFunctionContext } from '../types';\n\nexport type CaptureExistingTranslationsInput = {\n documents: SanityDocument[];\n localeIds: string[];\n secrets: Secrets;\n context: TranslationFunctionContext;\n branchId?: string;\n};\n\nexport type CaptureExistingTranslationsResult = {\n /** Number of (document, locale) translations uploaded. */\n capturedCount: number;\n /** Number of documents that had at least one translation uploaded. */\n documentCount: number;\n};\n\nconst EMPTY_RESULT: CaptureExistingTranslationsResult = {\n capturedCount: 0,\n documentCount: 0,\n};\n\n/**\n * Upload the translations Sanity currently holds as the stored translation for\n * the source version General Translation already has, so a later translation of\n * a newer source version reuses them instead of regenerating.\n *\n * Must run before the current source revision is uploaded: the target version is\n * whatever General Translation holds now, which the upload would advance.\n * Documents with no source file there yet are skipped.\n */\nexport async function captureExistingTranslations({\n documents,\n localeIds,\n secrets,\n context,\n branchId,\n}: CaptureExistingTranslationsInput): Promise<CaptureExistingTranslationsResult> {\n if (documents.length === 0 || localeIds.length === 0) {\n return EMPTY_RESULT;\n }\n\n overrideConfig(secrets);\n const sourceLocale = gt.sourceLocale || libraryDefaultLocale;\n\n const seedFiles = await gt.downloadFileBatch(\n documents.map((document) => ({\n fileId: getDocumentPublishedId(document),\n branchId,\n }))\n );\n const seedByFileId = new Map(\n (seedFiles.files ?? []).map((file) => [file.fileId, file])\n );\n\n const existing = await collectExistingTranslations(\n documents.filter((document) =>\n seedByFileId.has(getDocumentPublishedId(document))\n ),\n localeIds,\n context\n );\n\n const files = Array.from(existing.entries()).flatMap(\n ([documentId, translations]) => {\n const seed = seedByFileId.get(documentId);\n if (!seed || translations.length === 0) {\n return [];\n }\n const fileName = seed.fileName ?? `sanity/${documentId}`;\n const reference = {\n fileName,\n fileFormat: 'HTML' as const,\n fileId: seed.fileId,\n versionId: seed.versionId,\n branchId: seed.branchId,\n };\n\n return [\n {\n source: { ...reference, content: seed.data, locale: sourceLocale },\n translations: translations.map(({ locale, content }) => ({\n ...reference,\n content,\n locale,\n })),\n },\n ];\n }\n );\n\n if (files.length === 0) {\n return EMPTY_RESULT;\n }\n\n await gt.uploadTranslations(files, { sourceLocale });\n\n return {\n capturedCount: files.reduce(\n (total, file) => total + file.translations.length,\n 0\n ),\n documentCount: files.length,\n };\n}\n","import type { GTFile, Secrets } from '../types';\nimport { gt, overrideConfig } from '../adapter/core';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport type { SerializedDocument } from '../serialization/types';\nimport type { ExistingTranslation } from './collectExistingTranslations';\n\n/**\n * Upload translations that already exist in Sanity for previously serialized\n * source documents. The endpoint is an upsert, so the Sanity content becomes\n * the stored translation for the source's fileId/versionId β€” this is how\n * human edits are preserved before (re-)enqueueing machine translation.\n *\n * Mirrors the CLI's upload workflow: each translation reuses the source\n * document's fileId and versionId and differs only by locale.\n */\nexport async function uploadTranslations(\n documents: {\n info: GTFile;\n serializedDocument: SerializedDocument;\n translations: ExistingTranslation[];\n }[],\n secrets: Secrets | null\n): Promise<Awaited<ReturnType<typeof gt.uploadTranslations>> | null> {\n const withTranslations = documents.filter(\n (document) => document.translations.length > 0\n );\n if (withTranslations.length === 0) {\n return null;\n }\n\n overrideConfig(secrets);\n const sourceLocale = gt.sourceLocale || libraryDefaultLocale;\n return await gt.uploadTranslations(\n withTranslations.map(({ info, serializedDocument, translations }) => ({\n source: {\n content: serializedDocument.content,\n fileName: `sanity/${info.documentId}`,\n fileId: info.documentId,\n fileFormat: 'HTML' as const,\n locale: sourceLocale,\n versionId: info.versionId || undefined,\n },\n translations: translations.map(({ locale, content }) => ({\n content,\n fileName: `sanity/${info.documentId}`,\n fileId: info.documentId,\n fileFormat: 'HTML' as const,\n locale,\n versionId: info.versionId || undefined,\n })),\n })),\n { sourceLocale }\n );\n}\n","import { gt, overrideConfig } from '../adapter/core';\nimport { FileProperties } from '../adapter/types';\nimport { DownloadedFile } from 'generaltranslation/types';\nimport type { Secrets } from '../types';\n\n/**\n * Downloads multiple translation files in a single batch request\n * @param files - Array of files to download with their output paths\n * @param maxRetries - Maximum number of retry attempts\n * @param retryDelay - Delay between retries in milliseconds\n * @returns Object containing successful and failed file IDs\n */\nexport async function downloadTranslations(\n files: FileProperties[],\n secrets: Secrets,\n maxRetries = 3,\n retryDelay = 1000\n): Promise<DownloadedFile[]> {\n overrideConfig(secrets);\n let retries = 0;\n\n while (retries <= maxRetries) {\n try {\n // Download the files\n const responseData = await gt.downloadFileBatch(\n files.map((file) => ({\n fileId: file.fileId,\n branchId: file.branchId,\n versionId: file.versionId,\n locale: file.locale,\n }))\n );\n const downloadedFiles = responseData.files || [];\n return downloadedFiles;\n } catch {\n // Increment retry counter and wait before next attempt\n retries++;\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\n }\n }\n\n return [];\n}\n","import type { Secrets } from '../types';\nimport { gt, overrideConfig } from '../adapter/core';\nimport { FileProperties } from '../adapter/types';\nimport {\n createStableTranslationKey,\n createTranslationStatusKey,\n} from '../utils/documentIds';\n\nexport async function checkTranslationStatus(\n fileQueryData: FileProperties[],\n downloadStatus: {\n downloaded: Set<string>;\n failed: Set<string>;\n skipped: Set<string>;\n },\n secrets: Secrets\n) {\n overrideConfig(secrets);\n try {\n // Only query for files that haven't been downloaded yet\n const currentQueryData = fileQueryData.filter((item) => {\n const statusKey = createTranslationStatusKey(\n item.branchId,\n item.fileId,\n item.versionId,\n item.locale\n );\n const stableKey = createStableTranslationKey(\n item.branchId,\n item.fileId,\n item.locale\n );\n return (\n !downloadStatus.downloaded.has(statusKey) &&\n !downloadStatus.downloaded.has(stableKey) &&\n !downloadStatus.failed.has(statusKey) &&\n !downloadStatus.failed.has(stableKey) &&\n !downloadStatus.skipped.has(statusKey) &&\n !downloadStatus.skipped.has(stableKey)\n );\n });\n\n // If all files have been downloaded, we're done\n if (currentQueryData.length === 0) {\n return true;\n }\n // Check for translations\n const responseData = await gt.queryFileData({\n translatedFiles: currentQueryData,\n });\n\n const translations = responseData.translatedFiles || [];\n\n // Filter for ready translations\n const readyTranslations = translations.filter(\n (translation) => translation.completedAt\n );\n\n return readyTranslations;\n } catch (error) {\n console.error('Error checking translation status', error);\n return [];\n }\n}\n","import type { GTFile, TranslationFunctionContext } from '../types';\nimport { deserializeDocument } from '../utils/serialize';\nimport { getTranslationStrategyForType } from './strategy';\n\nexport async function importDocument(\n docInfo: GTFile,\n localeId: string,\n document: string,\n context: TranslationFunctionContext,\n mergeWithTargetLocale: boolean = false\n) {\n const { client } = context;\n const deserialized = deserializeDocument(document);\n // The serialized HTML carries the document `_type` as a <meta> tag, so the\n // deserialized doc tells us which strategy to import with. versionId is not\n // used for the patch since the _rev travels inside the deserialized HTML.\n const strategy = getTranslationStrategyForType(\n deserialized._type as string | undefined\n );\n return strategy.patch(\n docInfo,\n deserialized,\n localeId,\n client,\n mergeWithTargetLocale\n );\n}\n","import { SanityClient, SanityDocument } from 'sanity';\nimport { pluginConfig } from '../adapter/core';\nimport { getPublishedId } from '../utils/documentIds';\nimport {\n metadataTranslationRef,\n metadataTranslations,\n TRANSLATION_METADATA_TYPE,\n} from '../utils/translationMetadata';\n\ninterface Reference {\n _type: 'reference';\n _ref: string;\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst isReference = (value: unknown): value is Reference =>\n isRecord(value) &&\n value._type === 'reference' &&\n typeof value._ref === 'string';\n\n/**\n * Function that:\n * 1. Finds all references in the document\n * 2. Fetches the referenced documents, looks for the translation.metadata file for each reference\n * 3. Updates the document reference with the other translated document reference\n * 4. Returns the document with the updated references\n */\nexport async function resolveRefs(\n doc: SanityDocument,\n locale: string,\n client: SanityClient\n) {\n const references = findReferences(doc);\n\n if (references.length === 0) {\n return doc;\n }\n\n const translatedRefs = await resolveTranslatedReferences(\n references,\n locale,\n client\n );\n return updateDocumentReferences(doc, translatedRefs);\n}\n\n/**\n * Write resolved references back without publishing them.\n *\n * `findLatestDraft` falls back to the published document when no draft exists,\n * which is the normal state for a translation that has already been published.\n * Patching that id would put the rewritten references live with no review step,\n * so seed a draft from the published state and patch that instead β€” the same\n * approach `internationalizedArrayPatch` takes.\n *\n * System fields are dropped from the patch: only the resolved content should be\n * written, and `_id` / `_rev` are the document's identity, not its content.\n */\nexport async function commitResolvedRefs(\n translatedDoc: SanityDocument,\n resolvedDoc: SanityDocument,\n client: SanityClient\n): Promise<void> {\n const {\n _id: _resolvedId,\n _rev: _resolvedRev,\n _createdAt: _resolvedCreatedAt,\n _updatedAt: _resolvedUpdatedAt,\n ...changes\n } = resolvedDoc;\n\n if (translatedDoc._id.startsWith('drafts.')) {\n await client.patch(translatedDoc._id).set(changes).commit();\n return;\n }\n\n const draftId = `drafts.${getPublishedId(translatedDoc._id)}`;\n await client\n .transaction()\n .createIfNotExists({ ...translatedDoc, _id: draftId })\n .patch(draftId, (patch) => patch.set(changes))\n .commit();\n}\n\n/**\n * Recursively finds all references in a document or object\n */\nfunction findReferences(\n obj: unknown,\n path: string[] = []\n): { ref: Reference; path: string[] }[] {\n if (!obj || typeof obj !== 'object') {\n return [];\n }\n\n const references: { ref: Reference; path: string[] }[] = [];\n\n if (isReference(obj)) {\n references.push({ ref: obj, path });\n }\n\n if (Array.isArray(obj)) {\n obj.forEach((item, index) => {\n references.push(...findReferences(item, [...path, index.toString()]));\n });\n } else if (isRecord(obj)) {\n Object.keys(obj).forEach((key) => {\n references.push(...findReferences(obj[key], [...path, key]));\n });\n }\n\n return references;\n}\n\n/**\n * Fetches translation metadata and resolves translated references\n */\nasync function resolveTranslatedReferences(\n references: { ref: Reference; path: string[] }[],\n locale: string,\n client: SanityClient\n): Promise<Map<string, string>> {\n const refIds = references.map((r) => r.ref._ref);\n const translatedRefs = new Map<string, string>();\n\n if (refIds.length === 0) {\n return translatedRefs;\n }\n\n const sourceLocale = pluginConfig.getSourceLocale();\n\n // Optimized GROQ query that directly returns only the needed translation pairs\n const query = `*[_type == \"${TRANSLATION_METADATA_TYPE}\" && count(${metadataTranslations('== $sourceLocale', 'value._ref in $refIds')}) > 0] {\n \"originalRef\": ${metadataTranslationRef('$sourceLocale')},\n \"translatedRefs\": ${metadataTranslations('== $locale')}.value._ref\n }[defined(originalRef) && count(translatedRefs) > 0]`;\n\n const translationPairs: { originalRef: string; translatedRefs: string[] }[] =\n await client.fetch(query, { refIds, sourceLocale, locale });\n\n // Build the translation map\n for (const { originalRef, translatedRefs: localeRefs } of translationPairs) {\n const translatedRef = localeRefs[localeRefs.length - 1];\n translatedRefs.set(originalRef, translatedRef);\n }\n\n return translatedRefs;\n}\n\n/**\n * Updates document references with their translated versions\n */\nfunction updateDocumentReferences(\n doc: SanityDocument,\n translatedRefs: Map<string, string>\n): SanityDocument {\n return updateReferencesRecursive(doc, translatedRefs) as SanityDocument;\n}\n\n/**\n * Recursively updates references in an object\n */\nfunction updateReferencesRecursive(\n obj: unknown,\n translatedRefs: Map<string, string>\n): unknown {\n if (!obj || typeof obj !== 'object') {\n return obj;\n }\n\n if (isReference(obj) && translatedRefs.has(obj._ref)) {\n return {\n ...obj,\n _ref: translatedRefs.get(obj._ref),\n };\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => updateReferencesRecursive(item, translatedRefs));\n }\n\n const updated: Record<string, unknown> = {};\n Object.keys(obj).forEach((key) => {\n updated[key] = updateReferencesRecursive(\n (obj as Record<string, unknown>)[key],\n translatedRefs\n );\n });\n\n return updated;\n}\n","import { SanityClient } from 'sanity';\nimport { pluginConfig } from '../adapter/core';\nimport { getPublishedId } from '../utils/documentIds';\nimport { findLatestDraft } from '../configuration/utils/findLatestDraft';\n\nexport async function findTranslatedDocuments(\n documentId: string,\n client: SanityClient\n) {\n const documents = await client.fetch(\n `*[_type == \"translation.metadata\" && references($documentId)]`\n );\n return documents;\n}\n\nexport async function findTranslatedDocumentForLocale(\n sourceDocumentId: string,\n localeId: string,\n client: SanityClient\n) {\n const cleanDocId = getPublishedId(sourceDocumentId);\n\n // Use the last locale entry defensively. Older versions could create\n // duplicate locale entries when bulk imports raced.\n const query = `*[\n _type == \"translation.metadata\" &&\n (\n translations[language == $sourceLocale][0].value._ref == $cleanDocId\n ) &&\n defined(translations[language == $localeId])\n ][0].translations[language == $localeId].value._ref`;\n\n const translatedDocIds = await client.fetch(query, {\n sourceLocale: pluginConfig.getSourceLocale(),\n cleanDocId,\n localeId,\n });\n\n const translatedDocId = translatedDocIds?.[translatedDocIds.length - 1];\n if (!translatedDocId) return null;\n\n return (await findLatestDraft(translatedDocId, client)) || null;\n}\n\nexport async function findDocument(documentId: string, client: SanityClient) {\n const query = `*[_id == $id]`;\n const params = { id: documentId };\n const document = await client.fetch(query, params);\n return document[0] || null;\n}\n","import { GTFile, TranslationFunctionContext } from '../types';\nimport { pluginConfig } from '../adapter/core';\nimport { importDocument } from '../translation/importDocument';\nimport { getPublishedId } from './documentIds';\n\nexport interface BatchProcessorOptions<T = unknown, R = unknown> {\n batchSize?: number;\n getConcurrencyKey?: (item: T) => string | undefined;\n onProgress?: (current: number, total: number) => void;\n onItemSuccess?: (item: T, result: R) => void;\n onItemFailure?: (item: T, error: unknown) => void;\n}\n\nexport interface ImportBatchItem {\n docInfo: GTFile;\n locale: string;\n data: string;\n translationContext: TranslationFunctionContext;\n key: string;\n}\n\nexport async function processBatch<T, R = unknown>(\n items: T[],\n processor: (item: T) => R | Promise<R>,\n options: BatchProcessorOptions<T, Awaited<R>> = {}\n): Promise<{\n successCount: number;\n failureCount: number;\n successfulItems: Awaited<R>[];\n failedItems: { item: T; error: unknown }[];\n}> {\n const {\n batchSize = 20,\n getConcurrencyKey,\n onProgress,\n onItemSuccess,\n onItemFailure,\n } = options;\n\n let successCount = 0;\n let failureCount = 0;\n const successfulItems: Awaited<R>[] = [];\n const failedItems: { item: T; error: unknown }[] = [];\n\n for (let i = 0; i < items.length; i += batchSize) {\n const batch = items.slice(i, i + batchSize);\n\n const pendingByKey = new Map<string, Promise<void>>();\n\n const batchPromises: Promise<\n | { success: true; item: T; result: Awaited<R> }\n | { success: false; item: T; error: unknown }\n >[] = batch.map(async (item) => {\n const concurrencyKey = getConcurrencyKey?.(item);\n const pending = concurrencyKey\n ? pendingByKey.get(concurrencyKey)\n : undefined;\n\n let release: () => void = () => {};\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n\n if (concurrencyKey) {\n pendingByKey.set(concurrencyKey, current);\n }\n\n try {\n if (pending) {\n await pending;\n }\n\n const result = await processor(item);\n onItemSuccess?.(item, result);\n return { success: true as const, item, result };\n } catch (error) {\n onItemFailure?.(item, error);\n return { success: false as const, item, error };\n } finally {\n release();\n if (concurrencyKey && pendingByKey.get(concurrencyKey) === current) {\n pendingByKey.delete(concurrencyKey);\n }\n }\n });\n\n const batchResults = await Promise.all(batchPromises);\n\n batchResults.forEach((result) => {\n if (result.success) {\n successCount++;\n successfulItems.push(result.result);\n } else {\n failureCount++;\n failedItems.push({ item: result.item, error: result.error });\n }\n });\n\n onProgress?.(i + batch.length, items.length);\n }\n\n return { successCount, failureCount, successfulItems, failedItems };\n}\n\nexport async function processImportBatch(\n items: ImportBatchItem[],\n options: BatchProcessorOptions<ImportBatchItem, string> = {}\n): Promise<{\n successCount: number;\n failureCount: number;\n successfulImports: string[];\n failedItems: { item: ImportBatchItem; error: unknown }[];\n}> {\n const successfulImports: string[] = [];\n\n const result = await processBatch(\n items,\n async (item: ImportBatchItem) => {\n await importDocument(\n item.docInfo,\n item.locale,\n item.data,\n item.translationContext,\n false\n );\n return item.key;\n },\n {\n ...options,\n // Serialize all locales of the same document when imports may patch the\n // source document in place: internationalized-array imports do a\n // read-merge-set, so concurrent locale imports would clobber each other\n // (last write wins). Document-level imports write to separate per-locale\n // documents and stay parallel. In 'mixed' mode the per-document strategy\n // is only known after deserialization, so serialize conservatively.\n getConcurrencyKey: (item: ImportBatchItem) =>\n pluginConfig.getTranslationLevel() === 'document'\n ? undefined\n : getPublishedId(item.docInfo.documentId),\n onItemSuccess: (item: ImportBatchItem, key: string) => {\n successfulImports.push(key);\n options.onItemSuccess?.(item, key);\n },\n onItemFailure: (item: ImportBatchItem, error: unknown) => {\n console.error(\n `Failed to import ${item.docInfo.documentId} (${item.locale}):`,\n error\n );\n options.onItemFailure?.(item, error);\n },\n }\n );\n\n return {\n ...result,\n successfulImports,\n };\n}\n","import { Secrets, TranslationFunctionContext } from '../types';\nimport { downloadTranslations } from '../translation/downloadTranslations';\nimport { processImportBatch, ImportBatchItem } from './batchProcessor';\nimport type { FileProperties, TranslationStatus } from '../adapter/types';\nimport { createStableTranslationKey, getPublishedId } from './documentIds';\n\nexport interface ImportResult {\n successCount: number;\n failureCount: number;\n successfulImports: string[];\n}\n\n/** A status that has passed the ready check, so its `fileData` is present. */\nexport type ReadyTranslationStatus = TranslationStatus & {\n fileData: FileProperties;\n};\n\nexport interface ImportOptions {\n filterReadyFiles?: (key: string, status: ReadyTranslationStatus) => boolean;\n onProgress?: (current: number, total: number) => void;\n /**\n * The translation-status keys selected for import, reported before any\n * downloading starts. These come straight from the status map, which is what\n * the locale rows are indexed by, so a caller can light up a row without\n * rederiving anything. `onImportSuccess` builds its key from the downloaded\n * file; the two agree today, and reporting the map keys here keeps that from\n * being load-bearing.\n */\n onSelectedKeys?: (statusKeys: string[]) => void;\n onImportSuccess?: (key: string) => void;\n}\n\nexport async function getReadyFilesForImport(\n translationStatuses: Map<string, TranslationStatus>,\n options: ImportOptions = {}\n): Promise<FileProperties[]> {\n const { filterReadyFiles = () => true } = options;\n const readyFilesByDocumentLocale = new Map<string, FileProperties>();\n const selectedStatusKeys: string[] = [];\n\n for (const [key, status] of translationStatuses.entries()) {\n const readyStatus =\n status.isReady && status.fileData\n ? ({ ...status, fileData: status.fileData } as ReadyTranslationStatus)\n : null;\n if (readyStatus && filterReadyFiles(key, readyStatus)) {\n selectedStatusKeys.push(key);\n const fileData = {\n fileId: getPublishedId(readyStatus.fileData.fileId),\n versionId: readyStatus.fileData.versionId,\n branchId: readyStatus.fileData.branchId,\n locale: readyStatus.fileData.locale,\n };\n readyFilesByDocumentLocale.set(\n createStableTranslationKey(\n fileData.branchId,\n fileData.fileId,\n fileData.locale\n ),\n fileData\n );\n }\n }\n\n options.onSelectedKeys?.(selectedStatusKeys);\n\n return Array.from(readyFilesByDocumentLocale.values());\n}\n\n/**\n * Identifies one file+locale across an import. Derived the same way for the\n * files queued up front and the files that come back from the download, so\n * `onImportStart` and `onImportSuccess` always agree on a key.\n */\nfunction importKeyFor(file: {\n branchId?: string;\n fileId?: string;\n versionId?: string;\n locale?: string | null;\n}): string {\n return `${file.branchId}:${file.fileId}:${file.versionId}:${file.locale}`;\n}\n\nexport async function importTranslations(\n readyFiles: FileProperties[],\n secrets: Secrets,\n translationContext: TranslationFunctionContext,\n options: ImportOptions = {}\n): Promise<ImportResult> {\n if (readyFiles.length === 0) {\n return { successCount: 0, failureCount: 0, successfulImports: [] };\n }\n\n const downloadedFiles = await downloadTranslations(readyFiles, secrets);\n\n const importItems: ImportBatchItem[] = downloadedFiles.map((file) => {\n const data =\n typeof file.data === 'string'\n ? file.data\n : JSON.stringify(file.data ?? '');\n return {\n docInfo: {\n documentId: file.fileId,\n versionId: file.versionId,\n },\n locale: file.locale!,\n data,\n translationContext,\n key: importKeyFor(file),\n };\n });\n\n const result = await processImportBatch(importItems, {\n onProgress: options.onProgress,\n onItemSuccess: (item, key) => {\n options.onImportSuccess?.(key);\n },\n });\n\n return {\n successCount: result.successCount,\n failureCount: result.failureCount,\n successfulImports: result.successfulImports,\n };\n}\n","import { SanityClient } from 'sanity';\nimport { processBatch } from '../utils/batchProcessor';\nimport { findDocument } from './findDocuments';\nimport { getPublishedId } from '../utils/documentIds';\n\n/**\n * Selects the translation documents belonging to a set of source documents.\n *\n * A document is classified as a source by its id, never by the `language`\n * label on its metadata entry. Locale codes get renamed β€” `en` to `en-US`, say\n * β€” and entries written beforehand keep the old code, so a group whose source\n * label no longer matches the configured source locale would be skipped\n * entirely and its source would be mistaken for a translation.\n *\n * The two id sets answer different questions:\n *\n * - `$publishedDocumentIds` β€” which groups are in scope. There is nothing to\n * publish until the source itself exists published.\n * - `$sourceDocumentIds` β€” what counts as a source. Every source under\n * management, including ones that only exist as a draft, so a source is\n * never returned as a translation of some other document.\n *\n * Known limitation: a group is in scope if it references any requested source,\n * so metadata that wrongly links two sources into one group can return the\n * other source's translations. Which source owns a translation is not\n * recoverable from the metadata once it is inconsistent, and the alternative β€”\n * skipping ambiguous groups β€” silently drops valid translations, which is the\n * worse outcome.\n */\nexport const TRANSLATION_DOCS_FOR_PUBLISH_QUERY = `*[\n _type == 'translation.metadata' &&\n count(translations[defined(value._ref) && value._ref in $publishedDocumentIds]) > 0\n] {\n 'translationDocs': translations[\n defined(value._ref) && !(value._ref in $sourceDocumentIds)\n ]{\n _key,\n 'docId': value._ref\n }\n}`;\n\nexport async function publishDocument(\n documentId: string,\n client: SanityClient\n) {\n try {\n // only publish if the document is a draft\n if (documentId.startsWith('drafts.')) {\n await client.action(\n {\n actionType: 'sanity.action.document.publish',\n draftId: documentId,\n publishedId: getPublishedId(documentId),\n },\n {}\n );\n }\n } catch (error) {\n console.error('Error publishing document', error);\n }\n}\n\nexport async function publishTranslations(\n documentIds: string[],\n client: SanityClient\n) {\n const publishedDocumentIds: string[] = [];\n await processBatch(\n documentIds,\n async (documentId) => {\n const document = await findDocument(`drafts.${documentId}`, client);\n if (!document) {\n return { documentId, published: false };\n }\n await publishDocument(document._id, client);\n publishedDocumentIds.push(documentId);\n return { documentId, published: true };\n },\n {\n onItemFailure: (documentId, error) => {\n console.error(`Failed to publish document ${documentId}:`, error);\n },\n }\n );\n return publishedDocumentIds;\n}\n","import type { Adapter, Secrets } from '../types';\nimport { gt, pluginConfig } from './core';\n\n// note: this function is used to get the available locales for a project\nexport const getLocales: Adapter['getLocales'] = async (\n _secrets: Secrets | null\n) => {\n return pluginConfig.getLocales().map((locale: string) => ({\n localeId: locale,\n description: gt.getLocaleProperties(locale).name,\n enabled: true,\n }));\n};\n","import type { TranslationPreferences } from '../adapter/types';\n\n/**\n * These are user preferences, not run state, so they persist across sessions\n * rather than resetting with the tab. Plugin config sets the starting point;\n * once the user touches a switch, their choice wins. Keyed by project + dataset\n * so Studios sharing an origin don't collide.\n */\nexport const getPreferencesStorageKey = (\n projectId: string | undefined,\n dataset: string | undefined\n) => `gt-sanity:preferences:${projectId ?? ''}:${dataset ?? ''}`;\n\nconst isPlainRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * Read the stored preferences, falling back to `defaults` for anything the\n * stored object doesn't specify.\n */\nexport function readPreferences(\n storageKey: string,\n defaults: TranslationPreferences\n): TranslationPreferences {\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (!raw) return defaults;\n const parsed: unknown = JSON.parse(raw);\n if (!isPlainRecord(parsed)) return defaults;\n // Merge per key: a preference added in a later release falls back to its\n // default instead of being dropped by a stale stored object.\n const merged = { ...defaults };\n const keys = Object.keys(defaults) as (keyof TranslationPreferences)[];\n for (const key of keys) {\n const value = parsed[key];\n if (typeof value === 'boolean') merged[key] = value;\n }\n return merged;\n } catch {\n return defaults;\n }\n}\n\nexport function writePreferences(\n storageKey: string,\n value: TranslationPreferences\n): void {\n try {\n window.localStorage.setItem(storageKey, JSON.stringify(value));\n } catch {\n // localStorage unavailable (SSR, private mode, quota) β€” the choice still\n // applies, it just won't survive a reload.\n }\n}\n","import React, {\n createContext,\n useContext,\n useState,\n useCallback,\n useEffect,\n useRef,\n ReactNode,\n} from 'react';\nimport { SanityDocument, useSchema } from 'sanity';\nimport { useToast } from '@sanity/ui/toast';\nimport { useClient } from '../hooks/useClient';\nimport { useSecrets } from '../hooks/useSecrets';\nimport {\n GTFile,\n Secrets,\n TranslationLocale,\n TranslationFunctionContext,\n} from '../types';\nimport { gt, overrideConfig, pluginConfig } from '../adapter/core';\nimport { getTranslationStrategy } from '../translation/strategy';\nimport { uploadFiles } from '../translation/uploadFiles';\nimport { initProject } from '../translation/initProject';\nimport { createJobs } from '../translation/createJobs';\nimport { captureExistingTranslations } from '../translation/captureExistingTranslations';\nimport { collectExistingTranslations } from '../translation/collectExistingTranslations';\nimport { uploadTranslations } from '../translation/uploadTranslations';\nimport { downloadTranslations } from '../translation/downloadTranslations';\nimport { checkTranslationStatus } from '../translation/checkTranslationStatus';\nimport { importDocument } from '../translation/importDocument';\nimport { commitResolvedRefs, resolveRefs } from '../sanity-api/resolveRefs';\nimport { findTranslatedDocumentForLocale } from '../sanity-api/findDocuments';\nimport {\n getReadyFilesForImport,\n importTranslations,\n ImportOptions,\n} from '../utils/importUtils';\nimport { processBatch } from '../utils/batchProcessor';\nimport {\n publishTranslations,\n TRANSLATION_DOCS_FOR_PUBLISH_QUERY,\n} from '../sanity-api/publishDocuments';\nimport { getLocales } from '../adapter/getLocales';\nimport type {\n FileProperties,\n TranslationPreferences,\n TranslationStatus,\n} from '../adapter/types';\nimport {\n createStableTranslationKey,\n createTranslationStatusKey,\n dedupeDocumentsPreferDraft,\n getDocumentPublishedId,\n getPublishedId,\n} from '../utils/documentIds';\nimport {\n getPreferencesStorageKey,\n readPreferences,\n writePreferences,\n} from '../utils/translationPreferences';\n\ninterface ImportProgress {\n current: number;\n total: number;\n isImporting: boolean;\n}\n\ninterface DownloadStatus {\n downloaded: Set<string>;\n failed: Set<string>;\n skipped: Set<string>;\n}\n\ntype ExistingTranslationMetadata = {\n sourceDocId: string;\n existingTranslations?: string[];\n};\n\ntype TranslationDocumentMetadata = {\n translationDocs?: { docId?: string }[];\n};\n\nexport type TranslateAllOptions = {\n /**\n * Discard the translations GT already holds and retranslate from source.\n * Also skips capturing Studio-side edits β€” capturing them would immediately\n * be reused as the baseline, which is the opposite of what a retranslate is\n * asking for.\n */\n force?: boolean;\n};\n\ninterface TranslationsContextType {\n // State\n isBusy: boolean;\n documents: SanityDocument[];\n locales: TranslationLocale[];\n autoRefresh: boolean;\n autoImport: boolean;\n autoPatchReferences: boolean;\n autoPublish: boolean;\n preserveExistingTranslations: boolean;\n loadingDocuments: boolean;\n importProgress: ImportProgress;\n importedTranslations: Set<string>;\n existingTranslations: Set<string>;\n downloadStatus: DownloadStatus;\n translationStatuses: Map<string, TranslationStatus>;\n /**\n * Status keys enqueued this session and not yet reported ready. Non-empty\n * means General Translation is still working, which nothing else in the\n * status map distinguishes from \"never translated\" β€” both read as 0%.\n */\n pendingTranslations: Set<string>;\n /**\n * Status keys currently being written to Sanity. `importProgress` only counts\n * how many are done, so without this a locale row cannot tell \"queued in this\n * import\" from \"not part of it\" while a bulk import runs.\n */\n importingTranslations: Set<string>;\n isRefreshing: boolean;\n loadingSecrets: boolean;\n secrets: Secrets | null;\n branchId: string | undefined;\n // Version to use for translation status keys and GT file queries. Prefers\n // the _rev pinned at upload time over the live _rev, so in-place imports\n // (internationalized arrays) bumping the document _rev don't orphan the\n // statuses of the version actually uploaded to GT.\n getVersionId: (document: SanityDocument) => string;\n\n // Actions\n setLocales: (locales: TranslationLocale[]) => void;\n setAutoRefresh: (value: boolean) => void;\n setAutoImport: (value: boolean) => void;\n setAutoPatchReferences: (value: boolean) => void;\n setAutoPublish: (value: boolean) => void;\n setPreserveExistingTranslations: (value: boolean) => void;\n handleTranslateAll: (options?: TranslateAllOptions) => Promise<void>;\n handleUploadExistingTranslations: () => Promise<void>;\n handleImportAll: () => Promise<void>;\n handleImportMissing: () => Promise<void>;\n handleRefreshAll: (options?: { silent?: boolean }) => Promise<void>;\n handleImportDocument: (\n documentId: string,\n versionId: string,\n localeId: string\n ) => Promise<void>;\n handlePatchDocumentReferences: () => Promise<number>;\n handlePublishAllTranslations: () => Promise<number>;\n}\n\nconst TranslationsContext = createContext<TranslationsContextType | null>(null);\n\n// Pinned upload versions are mirrored to sessionStorage so they survive a\n// Studio page refresh: falling back to the live document._rev after a refresh\n// would query GT with a version that was never uploaded (in-place imports bump\n// the _rev), making completed translations show as \"not started\". Keyed by\n// project + dataset so Studios sharing an origin don't collide.\nconst getUploadedVersionsStorageKey = (\n projectId: string | undefined,\n dataset: string | undefined\n) => `gt-sanity:uploadedVersions:${projectId ?? ''}:${dataset ?? ''}`;\n\nfunction readUploadedVersions(storageKey: string): Map<string, string> {\n try {\n const raw = window.sessionStorage.getItem(storageKey);\n if (!raw) return new Map();\n const parsed: unknown = JSON.parse(raw);\n if (!isPlainRecord(parsed)) return new Map();\n return new Map(\n Object.entries(parsed).filter(\n (entry): entry is [string, string] => typeof entry[1] === 'string'\n )\n );\n } catch {\n return new Map();\n }\n}\n\nfunction writeUploadedVersions(\n storageKey: string,\n versions: Map<string, string>\n): void {\n try {\n window.sessionStorage.setItem(\n storageKey,\n JSON.stringify(Object.fromEntries(versions))\n );\n } catch {\n // sessionStorage unavailable (SSR, private mode, quota) β€” pinned versions\n // fall back to in-memory only.\n }\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport const useTranslations = () => {\n const context = useContext(TranslationsContext);\n if (!context) {\n throw new Error('useTranslations must be used within TranslationsProvider');\n }\n return context;\n};\n\ninterface TranslationsProviderProps {\n children: ReactNode;\n singleDocument?: SanityDocument | null;\n}\n\nexport const TranslationsProvider: React.FC<TranslationsProviderProps> = ({\n children,\n singleDocument,\n}) => {\n const [isBusy, setIsBusy] = useState(false);\n const [documents, setDocuments] = useState<SanityDocument[]>([]);\n const [locales, setLocales] = useState<TranslationLocale[]>([]);\n const [loadingDocuments, setLoadingDocuments] = useState(false);\n const [importProgress, setImportProgress] = useState<ImportProgress>({\n current: 0,\n total: 0,\n isImporting: false,\n });\n const [importedTranslations, setImportedTranslations] = useState<Set<string>>(\n new Set()\n );\n const [existingTranslations, setExistingTranslations] = useState<Set<string>>(\n new Set()\n );\n const [downloadStatus, setDownloadStatus] = useState<DownloadStatus>({\n downloaded: new Set<string>(),\n failed: new Set<string>(),\n skipped: new Set<string>(),\n });\n const downloadStatusRef = useRef(downloadStatus);\n const [translationStatuses, setTranslationStatuses] = useState<\n Map<string, TranslationStatus>\n >(new Map());\n const [pendingTranslations, setPendingTranslations] = useState<Set<string>>(\n new Set()\n );\n const [importingTranslations, setImportingTranslations] = useState<\n Set<string>\n >(new Set());\n const [isRefreshing, setIsRefreshing] = useState(false);\n\n const client = useClient();\n const { projectId, dataset } = client.config();\n const uploadedVersionsStorageKey = getUploadedVersionsStorageKey(\n projectId,\n dataset\n );\n const [uploadedVersions, setUploadedVersions] = useState<Map<string, string>>(\n () => readUploadedVersions(uploadedVersionsStorageKey)\n );\n const preferencesStorageKey = getPreferencesStorageKey(projectId, dataset);\n const [preferences, setPreferences] = useState<TranslationPreferences>(() =>\n readPreferences(preferencesStorageKey, pluginConfig.getPreferences())\n );\n const {\n autoRefresh,\n autoImport,\n autoPatchReferences,\n autoPublish,\n preserveExistingTranslations,\n } = preferences;\n\n // Persist from the event handler rather than an effect: these only ever\n // change in response to the user flipping a switch.\n const setPreference = useCallback(\n (key: keyof TranslationPreferences, value: boolean) => {\n const next = { ...preferences, [key]: value };\n setPreferences(next);\n writePreferences(preferencesStorageKey, next);\n },\n [preferences, preferencesStorageKey]\n );\n const setAutoRefresh = useCallback(\n (value: boolean) => setPreference('autoRefresh', value),\n [setPreference]\n );\n const setAutoImport = useCallback(\n (value: boolean) => setPreference('autoImport', value),\n [setPreference]\n );\n const setAutoPatchReferences = useCallback(\n (value: boolean) => setPreference('autoPatchReferences', value),\n [setPreference]\n );\n const setAutoPublish = useCallback(\n (value: boolean) => setPreference('autoPublish', value),\n [setPreference]\n );\n const setPreserveExistingTranslations = useCallback(\n (value: boolean) => setPreference('preserveExistingTranslations', value),\n [setPreference]\n );\n const schema = useSchema();\n const translationContext: TranslationFunctionContext = { client, schema };\n const toast = useToast();\n const { loading: loadingSecrets, secrets } = useSecrets<Secrets>(\n pluginConfig.getSecretsNamespace()\n );\n const [branchId, setBranchId] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n downloadStatusRef.current = downloadStatus;\n }, [downloadStatus]);\n\n const getVersionId = useCallback(\n (document: SanityDocument) =>\n uploadedVersions.get(getDocumentPublishedId(document)) ?? document._rev,\n [uploadedVersions]\n );\n\n const fetchDocuments = useCallback(async () => {\n setLoadingDocuments(true);\n try {\n if (singleDocument) {\n setDocuments([singleDocument]);\n return;\n }\n\n const translateDocuments = pluginConfig.getTranslateDocuments();\n\n const filterConditions = translateDocuments\n .map((filter) => {\n if (filter.type && filter.documentId) {\n return `(_type == \"${filter.type}\" && _id == \"${filter.documentId}\")`;\n } else if (filter.type) {\n return `_type == \"${filter.type}\"`;\n } else if (filter.documentId) {\n return `_id == \"${filter.documentId}\"`;\n }\n return null;\n })\n .filter(Boolean);\n\n const languageField = pluginConfig.getLanguageField();\n const sourceLocale = pluginConfig.getSourceLocale();\n const languageFilter = `(!defined(${languageField}) || ${languageField} == \"${sourceLocale}\")`;\n\n let query;\n if (filterConditions.length === 0) {\n query = `*[!(_type in [\"system.group\"]) && !(_id in path(\"_.**\")) && ${languageFilter}]`;\n } else {\n const filterQuery = filterConditions.join(' || ');\n query = `*[!(_type in [\"system.group\"]) && !(_id in path(\"_.**\")) && (${filterQuery}) && ${languageFilter}]`;\n }\n\n const docs = await client.fetch(query);\n setDocuments(dedupeDocumentsPreferDraft(docs));\n } catch {\n toast.push({\n title:\n 'Documents could not be loaded. Check your Sanity connection and try refreshing.',\n status: 'error',\n closable: true,\n });\n } finally {\n setLoadingDocuments(false);\n }\n }, [client, singleDocument]);\n\n const fetchLocales = useCallback(async () => {\n if (!secrets) return;\n try {\n const availableLocales = await getLocales(secrets);\n setLocales(availableLocales);\n } catch {\n toast.push({\n title:\n 'Locales could not be loaded. Check your General Translation credentials and try again.',\n status: 'error',\n closable: true,\n });\n }\n }, [secrets]);\n\n const fetchExistingTranslations = useCallback(async () => {\n if (!documents.length || !locales.length) return;\n\n try {\n const sourceLocale = pluginConfig.getSourceLocale();\n const availableLocaleIds = locales\n .filter((locale) => locale.enabled !== false)\n .map((locale) => locale.localeId);\n\n const documentIds = documents.map(getDocumentPublishedId);\n\n const query = `*[\n _type == 'translation.metadata' &&\n translations[language == $sourceLocale][0].value._ref in $documentIds\n ] {\n 'sourceDocId': translations[language == $sourceLocale][0].value._ref,\n 'existingTranslations': translations[language in $localeIds].language\n }`;\n\n const existingMetadata = await client.fetch<\n ExistingTranslationMetadata[]\n >(query, {\n sourceLocale,\n documentIds,\n localeIds: availableLocaleIds,\n });\n\n const existing = new Set<string>();\n existingMetadata.forEach((metadata) => {\n metadata.existingTranslations?.forEach((localeId: string) => {\n if (localeId !== sourceLocale) {\n existing.add(\n createStableTranslationKey(\n undefined,\n metadata.sourceDocId,\n localeId\n )\n );\n }\n });\n });\n\n setExistingTranslations(existing);\n } catch (error) {\n console.error('Error fetching existing translations:', error);\n toast.push({\n title:\n 'Existing translations could not be loaded. Try refreshing before importing.',\n status: 'error',\n closable: true,\n });\n }\n }, [documents, locales, client]);\n\n const serializeSourceDocuments = useCallback(\n () =>\n documents\n .map((doc) => {\n const { [pluginConfig.getLanguageField()]: _, ...cleanDoc } = doc;\n const baseLanguage = pluginConfig.getSourceLocale();\n try {\n const strategy = getTranslationStrategy(doc);\n return {\n info: {\n documentId: getDocumentPublishedId(doc),\n versionId: doc._rev,\n },\n serializedDocument: strategy.serialize(\n cleanDoc as typeof doc,\n schema,\n baseLanguage\n ),\n };\n } catch (error) {\n console.error('Error transforming document', doc._id, error);\n }\n return null;\n })\n .filter((doc) => doc !== null),\n [documents, schema]\n );\n\n const handleTranslateAll = useCallback(\n async ({ force = false }: TranslateAllOptions = {}) => {\n if (!secrets || documents.length === 0) return;\n\n setIsBusy(true);\n\n try {\n const availableLocaleIds = locales\n .filter((locale) => locale.enabled !== false)\n .map((locale) => locale.localeId);\n\n // Send any Studio-side edits to existing translations back to GT first,\n // pinned to the source version they belong to. This has to happen before\n // the upload below, which makes the new revision the latest version and\n // would leave the edits attached to nothing. Best-effort: a failure here\n // costs edit preservation, and must not block the translation itself.\n if (preserveExistingTranslations && !force) {\n try {\n const captured = await captureExistingTranslations({\n documents,\n localeIds: availableLocaleIds,\n secrets,\n context: translationContext,\n branchId,\n });\n if (captured.capturedCount > 0) {\n toast.push({\n title: `Preserved ${captured.capturedCount} existing translation(s) across ${captured.documentCount} document(s)`,\n status: 'info',\n closable: true,\n });\n }\n } catch (error) {\n console.error(\n 'Could not preserve existing translations. Continuing β€” edits made to translated documents may be overwritten by this run.',\n error\n );\n toast.push({\n title:\n 'Existing translations could not be preserved. Translation is continuing, but edits made to translated documents may be overwritten.',\n status: 'warning',\n closable: true,\n });\n }\n }\n\n const transformedDocuments = serializeSourceDocuments();\n\n const uploadResult = await uploadFiles(transformedDocuments, secrets);\n await initProject(uploadResult, { timeout: 600 }, secrets);\n await createJobs(uploadResult, availableLocaleIds, secrets, force);\n\n // Pin the _rev each file was uploaded under. GT status queries need the\n // exact uploaded versionId, and the live _rev moves on (in-place array\n // imports bump it), so status lookups go through getVersionId instead.\n // Persisted to sessionStorage so the pins survive a page refresh.\n const nextUploadedVersions = new Map(uploadedVersions);\n for (const { info } of transformedDocuments) {\n if (info.versionId) {\n nextUploadedVersions.set(info.documentId, info.versionId);\n }\n }\n writeUploadedVersions(uploadedVersionsStorageKey, nextUploadedVersions);\n setUploadedVersions(nextUploadedVersions);\n\n const enqueuedStatusKeys = new Set<string>();\n const enqueuedStableKeys = new Set<string>();\n for (const { info } of transformedDocuments) {\n for (const localeId of availableLocaleIds) {\n enqueuedStatusKeys.add(\n createTranslationStatusKey(\n branchId,\n info.documentId,\n info.versionId ?? '',\n localeId\n )\n );\n enqueuedStableKeys.add(\n createStableTranslationKey(branchId, info.documentId, localeId)\n );\n }\n }\n\n // A key already downloaded this session is skipped by the status\n // query, so re-translating one would leave it outstanding forever:\n // enqueued as pending, never reported ready, never cleared. Drop the\n // markers for everything being retranslated β€” the previous download is\n // superseded by the run starting now.\n setDownloadStatus((prev) => ({\n downloaded: new Set(\n [...prev.downloaded].filter(\n (key) =>\n !enqueuedStatusKeys.has(key) && !enqueuedStableKeys.has(key)\n )\n ),\n failed: new Set(\n [...prev.failed].filter(\n (key) =>\n !enqueuedStatusKeys.has(key) && !enqueuedStableKeys.has(key)\n )\n ),\n skipped: new Set(\n [...prev.skipped].filter(\n (key) =>\n !enqueuedStatusKeys.has(key) && !enqueuedStableKeys.has(key)\n )\n ),\n }));\n\n // Everything just enqueued is outstanding until a refresh reports it\n // ready. Without this the UI cannot tell \"General Translation is\n // working on it\" from \"never translated\" β€” both sit at 0%.\n setPendingTranslations(\n (prev) => new Set([...prev, ...enqueuedStatusKeys])\n );\n\n toast.push({\n title: force\n ? `Retranslating ${documents.length} documents from scratch`\n : `Translation tasks created for ${documents.length} documents`,\n status: 'success',\n closable: true,\n });\n } catch {\n toast.push({\n title:\n 'Translation tasks could not be created. No documents were changed. Try again or check the console for details.',\n status: 'error',\n closable: true,\n });\n } finally {\n setIsBusy(false);\n }\n },\n [\n secrets,\n documents,\n locales,\n schema,\n client,\n branchId,\n preserveExistingTranslations,\n serializeSourceDocuments,\n uploadedVersions,\n uploadedVersionsStorageKey,\n ]\n );\n\n const handleUploadExistingTranslations = useCallback(async () => {\n if (!secrets || documents.length === 0) return;\n\n setIsBusy(true);\n try {\n const availableLocaleIds = locales\n .filter((locale) => locale.enabled !== false)\n .map((locale) => locale.localeId);\n\n const transformedDocuments = serializeSourceDocuments();\n\n // Seed the source files first. uploadTranslations requires the source to\n // exist, and this action exists for projects whose translations predate\n // General Translation, where no source has been uploaded yet. Enqueueing\n // is deliberately skipped so nothing is retranslated.\n await uploadFiles(transformedDocuments, secrets);\n\n const existing = await collectExistingTranslations(\n documents,\n availableLocaleIds,\n translationContext\n );\n const withTranslations = transformedDocuments\n .map((document) => ({\n ...document,\n translations: existing.get(document.info.documentId) ?? [],\n }))\n .filter((document) => document.translations.length > 0);\n\n const response = await uploadTranslations(withTranslations, secrets);\n const count = response?.uploadedFiles.length ?? 0;\n\n toast.push({\n title:\n count > 0\n ? `Uploaded ${count} existing translation(s) across ${withTranslations.length} document(s)`\n : 'No existing translations found to upload',\n status: count > 0 ? 'success' : 'warning',\n closable: true,\n });\n } catch (error) {\n console.error('Error uploading existing translations:', error);\n toast.push({\n title:\n 'Existing translations could not be uploaded. No documents were changed. Try again or check the console for details.',\n status: 'error',\n closable: true,\n });\n } finally {\n setIsBusy(false);\n }\n }, [secrets, documents, locales, client, schema, serializeSourceDocuments]);\n\n const handleImportAll = useCallback(async () => {\n if (!secrets || documents.length === 0 || !branchId) return;\n\n setIsBusy(true);\n\n try {\n const readyFiles = await getReadyFilesForImport(translationStatuses, {\n onSelectedKeys: (keys) => setImportingTranslations(new Set(keys)),\n });\n\n if (readyFiles.length === 0) {\n toast.push({\n title: 'No ready translations to import',\n status: 'warning',\n closable: true,\n });\n return;\n }\n\n setImportProgress({\n current: 0,\n total: readyFiles.length,\n isImporting: true,\n });\n\n const importOptions: ImportOptions = {\n onProgress: (current, total) => {\n setImportProgress({\n current,\n total,\n isImporting: true,\n });\n },\n onImportSuccess: (key) => {\n setImportedTranslations((prev) => new Set([...prev, key]));\n },\n };\n\n const result = await importTranslations(\n readyFiles,\n secrets,\n translationContext,\n importOptions\n );\n\n if (result.successfulImports.length > 0) {\n setDownloadStatus((prev) => ({\n ...prev,\n downloaded: new Set([\n ...prev.downloaded,\n ...result.successfulImports,\n ]),\n }));\n }\n\n toast.push({\n title: `Imported ${result.successCount} translations${result.failureCount > 0 ? `, ${result.failureCount} failed` : ''}`,\n status: result.successCount > 0 ? 'success' : 'error',\n closable: true,\n });\n } catch (error) {\n console.error('Error importing translations:', error);\n toast.push({\n title:\n 'Translations could not be imported. No documents were changed. Try again or check the console for details.',\n status: 'error',\n closable: true,\n });\n } finally {\n setIsBusy(false);\n setImportProgress({ current: 0, total: 0, isImporting: false });\n setImportingTranslations(new Set());\n }\n }, [\n secrets,\n documents,\n translationStatuses,\n downloadStatus,\n translationContext,\n branchId,\n ]);\n\n const getExistingTranslations = useCallback(\n async (\n documentIds: string[],\n localeIds: string[],\n branchId: string\n ): Promise<Set<string>> => {\n const sourceLocale = pluginConfig.getSourceLocale();\n\n const query = `*[\n _type == 'translation.metadata' &&\n translations[language == $sourceLocale][0].value._ref in $documentIds\n ] {\n _rev,\n 'sourceDocId': translations[language == $sourceLocale][0].value._ref,\n 'existingTranslations': translations[language in $localeIds].language\n }`;\n\n const existingMetadata = await client.fetch<\n ExistingTranslationMetadata[]\n >(query, {\n sourceLocale,\n documentIds,\n localeIds,\n });\n\n const existing = new Set<string>();\n existingMetadata.forEach((metadata) => {\n metadata.existingTranslations?.forEach((localeId: string) => {\n if (localeId !== sourceLocale) {\n existing.add(\n createStableTranslationKey(\n branchId,\n metadata.sourceDocId,\n localeId\n )\n );\n }\n });\n });\n\n return existing;\n },\n [client]\n );\n\n const handleImportMissing = useCallback(async () => {\n if (!secrets || documents.length === 0 || !branchId) return;\n\n setIsBusy(true);\n\n try {\n const availableLocaleIds = locales\n .filter((locale) => locale.enabled !== false)\n .map((locale) => locale.localeId);\n\n const documentIds = documents.map(getDocumentPublishedId);\n\n const existingTranslations = await getExistingTranslations(\n documentIds,\n availableLocaleIds,\n branchId\n );\n\n const readyFiles = await getReadyFilesForImport(translationStatuses, {\n onSelectedKeys: (keys) => setImportingTranslations(new Set(keys)),\n filterReadyFiles: (_key, status) =>\n !existingTranslations.has(\n createStableTranslationKey(\n branchId,\n status.fileData.fileId,\n status.fileData.locale\n )\n ),\n });\n\n if (readyFiles.length === 0) {\n toast.push({\n title: 'No missing translations to import',\n status: 'warning',\n closable: true,\n });\n return;\n }\n\n setImportProgress({\n current: 0,\n total: readyFiles.length,\n isImporting: true,\n });\n\n const importOptions: ImportOptions = {\n onProgress: (current, total) => {\n setImportProgress({\n current,\n total,\n isImporting: true,\n });\n },\n onImportSuccess: (key) => {\n setImportedTranslations((prev) => new Set([...prev, key]));\n setExistingTranslations((prev) => new Set([...prev, key]));\n },\n };\n\n const result = await importTranslations(\n readyFiles,\n secrets,\n translationContext,\n importOptions\n );\n\n if (result.successfulImports.length > 0) {\n setDownloadStatus((prev) => ({\n ...prev,\n downloaded: new Set([\n ...prev.downloaded,\n ...result.successfulImports,\n ]),\n }));\n }\n\n toast.push({\n title: `Imported ${result.successCount} missing translations${result.failureCount > 0 ? `, ${result.failureCount} failed` : ''}`,\n status: result.successCount > 0 ? 'success' : 'error',\n closable: true,\n });\n } catch (error) {\n console.error('Error importing missing translations:', error);\n toast.push({\n title:\n 'Missing translations could not be imported. No documents were changed. Try again or check the console for details.',\n status: 'error',\n closable: true,\n });\n } finally {\n setIsBusy(false);\n setImportProgress({ current: 0, total: 0, isImporting: false });\n setImportingTranslations(new Set());\n }\n }, [\n secrets,\n documents,\n locales,\n translationStatuses,\n downloadStatus,\n translationContext,\n getExistingTranslations,\n branchId,\n ]);\n\n const handleGetBranchId = useCallback(\n async (secrets: Secrets) => {\n overrideConfig(secrets);\n const defaultBranch = await gt.createBranch({\n branchName: 'main',\n defaultBranch: true,\n });\n setBranchId(defaultBranch.branch.id);\n },\n [secrets]\n );\n\n // `silent` suppresses the success toast. The poll runs every 10 seconds, so\n // only a refresh the user asked for should announce itself.\n const handleRefreshAll = useCallback(\n async ({ silent = false }: { silent?: boolean } = {}) => {\n if (!secrets || documents.length === 0 || !branchId) return;\n setIsRefreshing(true);\n\n try {\n const availableLocaleIds = locales\n .filter((locale) => locale.enabled !== false)\n .map((locale) => locale.localeId);\n\n const fileQueryData: FileProperties[] = [];\n for (const doc of documents) {\n for (const localeId of availableLocaleIds) {\n const documentId = getDocumentPublishedId(doc);\n fileQueryData.push({\n versionId: getVersionId(doc),\n fileId: documentId,\n branchId: branchId,\n locale: localeId,\n });\n }\n }\n\n const readyTranslations = await checkTranslationStatus(\n fileQueryData,\n downloadStatusRef.current,\n secrets\n );\n\n // Built here rather than inside an updater: it derives from the\n // response, not from previous state, and a state updater has to stay\n // pure β€” React may run it more than once.\n const newStatuses = new Map<string, TranslationStatus>();\n\n for (const doc of documents) {\n for (const localeId of availableLocaleIds) {\n const documentId = getDocumentPublishedId(doc);\n const versionId = getVersionId(doc);\n const key = createTranslationStatusKey(\n branchId,\n documentId,\n versionId,\n localeId\n );\n newStatuses.set(key, { progress: 0, isReady: false });\n }\n }\n\n if (Array.isArray(readyTranslations)) {\n for (const translation of readyTranslations) {\n const key = createTranslationStatusKey(\n branchId,\n translation.fileId,\n translation.versionId,\n translation.locale\n );\n newStatuses.set(key, {\n progress: 100,\n isReady: true,\n fileData: {\n versionId: translation.versionId,\n fileId: translation.fileId,\n branchId: translation.branchId,\n locale: translation.locale,\n },\n });\n }\n }\n\n setTranslationStatuses(newStatuses);\n\n // A translation that has arrived is no longer outstanding.\n setPendingTranslations((prev) => {\n if (prev.size === 0) return prev;\n const next = new Set(prev);\n for (const [key, status] of newStatuses) {\n if (status.isReady) next.delete(key);\n }\n return next.size === prev.size ? prev : next;\n });\n\n if (!silent) {\n toast.push({\n title: `Refreshed status for ${documents.length} document(s)`,\n status: 'success',\n closable: true,\n });\n }\n } catch (error) {\n console.error('Error refreshing translation status:', error);\n toast.push({\n title:\n 'Translation status could not be refreshed. Try again before importing.',\n status: 'error',\n closable: true,\n });\n } finally {\n setIsRefreshing(false);\n }\n },\n [secrets, documents, locales, branchId, getVersionId]\n );\n\n const handleImportDocument = useCallback(\n async (documentId: string, versionId: string, localeId: string) => {\n if (!secrets) return;\n\n const key = createTranslationStatusKey(\n branchId,\n documentId,\n versionId,\n localeId\n );\n const status = translationStatuses.get(key);\n\n if (!status?.isReady || !status.fileData) {\n toast.push({\n title: `Translation not ready for ${documentId} (${localeId})`,\n status: 'warning',\n closable: true,\n });\n return;\n }\n\n const document = documents.find(\n (doc) => getDocumentPublishedId(doc) === getPublishedId(documentId)\n );\n\n if (!document) {\n toast.push({\n title: `Document ${documentId} not found`,\n status: 'error',\n closable: true,\n });\n return;\n }\n\n try {\n const downloadedFiles = await downloadTranslations(\n [\n {\n fileId: status.fileData.fileId,\n branchId: status.fileData.branchId,\n versionId: status.fileData.versionId,\n locale: status.fileData.locale,\n },\n ],\n secrets\n );\n\n if (downloadedFiles.length > 0) {\n try {\n const docInfo: GTFile = {\n documentId: getPublishedId(documentId),\n versionId: document._rev,\n };\n\n await importDocument(\n docInfo,\n localeId,\n downloadedFiles[0].data,\n translationContext,\n false\n );\n\n setDownloadStatus((prev) => ({\n ...prev,\n downloaded: new Set([...prev.downloaded, key]),\n }));\n setImportedTranslations((prev) => new Set([...prev, key]));\n setExistingTranslations(\n (prev) =>\n new Set([\n ...prev,\n createStableTranslationKey(branchId, documentId, localeId),\n ])\n );\n\n toast.push({\n title: `Successfully imported translation for ${documentId} (${localeId})`,\n status: 'success',\n closable: true,\n });\n } catch (importError) {\n console.error('Failed to import translation:', importError);\n toast.push({\n title: `Translation for ${documentId} (${localeId}) could not be imported. This document was not changed.`,\n status: 'error',\n closable: true,\n });\n }\n } else {\n toast.push({\n title: `No translation content received for ${documentId}`,\n status: 'warning',\n closable: true,\n });\n }\n } catch (error) {\n console.error('Error importing translation:', error);\n toast.push({\n title: `Translation for ${documentId} could not be imported. This document was not changed.`,\n status: 'error',\n closable: true,\n });\n }\n },\n [secrets, documents, translationContext, translationStatuses, branchId]\n );\n\n const handlePatchDocumentReferences = useCallback(async () => {\n if (!secrets || documents.length === 0) return 0;\n\n setIsBusy(true);\n\n try {\n const availableLocaleIds = locales\n .filter((locale) => locale.enabled !== false)\n .map((locale) => locale.localeId);\n\n const patchTasks: Array<{ doc: SanityDocument; localeId: string }> = [];\n for (const doc of documents) {\n for (const localeId of availableLocaleIds) {\n patchTasks.push({ doc, localeId });\n }\n }\n\n setImportProgress({\n current: 0,\n total: patchTasks.length,\n isImporting: true,\n });\n\n const result = await processBatch(\n patchTasks,\n async ({ doc, localeId }) => {\n const sourceLocale = pluginConfig.getSourceLocale();\n\n // Skip source locale - only process translated documents\n if (localeId === sourceLocale) {\n return { patched: false, doc, localeId, skipped: true };\n }\n\n // Find the translated document for this locale\n const translatedDoc = await findTranslatedDocumentForLocale(\n doc._id,\n localeId,\n client\n );\n\n if (!translatedDoc) {\n return { patched: false, doc, localeId, noTranslation: true };\n }\n\n const resolvedDoc = await resolveRefs(\n translatedDoc,\n localeId,\n client\n );\n\n if (resolvedDoc !== translatedDoc) {\n await commitResolvedRefs(translatedDoc, resolvedDoc, client);\n return { patched: true, doc: translatedDoc, localeId };\n }\n return { patched: false, doc: translatedDoc, localeId };\n },\n {\n onProgress: (current, total) => {\n setImportProgress({\n current,\n total,\n isImporting: true,\n });\n },\n onItemFailure: ({ doc, localeId }, error) => {\n console.error(\n `Failed to patch references for ${doc._id} (${localeId}):`,\n error\n );\n },\n }\n );\n\n const patchedCount = result.successfulItems.filter(\n (item) => item.patched\n ).length;\n\n toast.push({\n title: `Patched references in ${patchedCount} documents${result.failureCount > 0 ? `, ${result.failureCount} failed` : ''}`,\n status:\n patchedCount > 0 || result.failureCount === 0 ? 'success' : 'error',\n closable: true,\n });\n\n return patchedCount;\n } catch (error) {\n console.error('Error patching document references:', error);\n toast.push({\n title:\n 'Document references could not be updated. Imported translations may need to be linked manually.',\n status: 'error',\n closable: true,\n });\n return 0;\n } finally {\n setIsBusy(false);\n setImportProgress({ current: 0, total: 0, isImporting: false });\n }\n }, [secrets, documents, locales, client, branchId]);\n\n const handlePublishAllTranslations = useCallback(async () => {\n if (!secrets || documents.length === 0) return 0;\n\n setIsBusy(true);\n\n try {\n const sourceDocumentIds = documents.map(getDocumentPublishedId);\n const publishedDocumentIds = await client.fetch(\n `*[_id in $sourceDocumentIds]._id`,\n { sourceDocumentIds }\n );\n\n if (publishedDocumentIds.length === 0) {\n toast.push({\n title:\n 'No published source documents found to publish translations for',\n status: 'warning',\n closable: true,\n });\n return 0;\n }\n\n const translationMetadata = await client.fetch<\n TranslationDocumentMetadata[]\n >(TRANSLATION_DOCS_FOR_PUBLISH_QUERY, {\n publishedDocumentIds,\n sourceDocumentIds,\n });\n\n const translationDocIds = new Set<string>();\n translationMetadata.forEach((metadata) => {\n metadata.translationDocs?.forEach((translation) => {\n if (translation.docId) {\n translationDocIds.add(translation.docId);\n }\n });\n });\n\n const publishableIds = Array.from(translationDocIds);\n\n if (publishableIds.length === 0) {\n toast.push({\n title: 'No translation documents found to publish',\n status: 'warning',\n closable: true,\n });\n return 0;\n }\n\n const translatedDocumentIds = await publishTranslations(\n publishableIds,\n client\n );\n\n toast.push({\n title: `Published ${translatedDocumentIds.length} translation documents`,\n status: 'success',\n closable: true,\n });\n\n return translatedDocumentIds.length;\n } catch (error) {\n console.error('Error publishing translations:', error);\n toast.push({\n title:\n 'Translations could not be published. No unpublished source documents were changed.',\n status: 'error',\n closable: true,\n });\n return 0;\n } finally {\n setIsBusy(false);\n }\n }, [secrets, documents, client, branchId]);\n\n useEffect(() => {\n fetchDocuments();\n }, [fetchDocuments]);\n\n useEffect(() => {\n if (secrets) {\n fetchLocales();\n }\n }, [fetchLocales, secrets]);\n\n useEffect(() => {\n if (documents.length > 0 && locales.length > 0) {\n fetchExistingTranslations();\n }\n }, [fetchExistingTranslations]);\n\n useEffect(() => {\n if (\n documents.length > 0 &&\n locales.length > 0 &&\n secrets &&\n !loadingDocuments &&\n branchId\n ) {\n handleRefreshAll({ silent: true });\n }\n }, [\n documents,\n locales,\n secrets,\n loadingDocuments,\n branchId,\n handleRefreshAll,\n ]);\n\n useEffect(() => {\n if (!autoRefresh || documents.length === 0 || !secrets) return;\n\n const interval = setInterval(async () => {\n await handleRefreshAll({ silent: true });\n }, 10000);\n\n return () => clearInterval(interval);\n }, [autoRefresh, documents.length, secrets, handleRefreshAll]);\n\n useEffect(() => {\n setImportedTranslations(new Set(downloadStatus.downloaded));\n }, [downloadStatus.downloaded]);\n\n useEffect(() => {\n if (secrets) {\n handleGetBranchId(secrets);\n }\n }, [secrets, handleGetBranchId]);\n\n const contextValue: TranslationsContextType = {\n // State\n isBusy,\n documents,\n locales,\n autoRefresh,\n autoImport,\n autoPatchReferences,\n autoPublish,\n preserveExistingTranslations,\n loadingDocuments,\n importProgress,\n importedTranslations,\n existingTranslations,\n downloadStatus,\n translationStatuses,\n pendingTranslations,\n importingTranslations,\n isRefreshing,\n loadingSecrets,\n secrets,\n branchId,\n getVersionId,\n\n // Actions\n setLocales,\n setAutoRefresh,\n setAutoImport,\n setAutoPatchReferences,\n setAutoPublish,\n setPreserveExistingTranslations,\n handleTranslateAll,\n handleUploadExistingTranslations,\n handleImportAll,\n handleImportMissing,\n handleRefreshAll,\n handleImportDocument,\n handlePatchDocumentReferences,\n handlePublishAllTranslations,\n };\n\n return (\n <TranslationsContext.Provider value={contextValue}>\n {children}\n </TranslationsContext.Provider>\n );\n};\n","import React from 'react';\nimport { Box, Button, Card, Dialog, Flex, Stack, Text } from '@sanity/ui';\n\ninterface SaveLocalTranslationsDialogProps {\n isOpen: boolean;\n onClose: () => void;\n onConfirm: () => void;\n}\n\nexport const SaveLocalTranslationsDialog: React.FC<\n SaveLocalTranslationsDialogProps\n> = ({ isOpen, onClose, onConfirm }) => {\n if (!isOpen) return null;\n\n return (\n <Dialog\n header='Save local edits'\n id='save-local-translations-dialog'\n onClose={onClose}\n footer={\n <Box padding={3}>\n <Flex gap={2}>\n <Button text='Cancel' mode='ghost' onClick={onClose} />\n <Button text='Turn on' tone='primary' onClick={onConfirm} />\n </Flex>\n </Box>\n }\n >\n <Box padding={4}>\n <Stack gap={4}>\n <Text>\n Before each translation run, the translations currently in Sanity\n are sent to General Translation. Content whose source text has not\n changed is then reused from Sanity instead of being translated\n again, so edits made here are kept.\n </Text>\n\n <Card padding={3} radius={2} tone='caution' border>\n <Stack gap={3}>\n <Text size={1} weight='medium'>\n Sanity becomes the source of truth\n </Text>\n <Text size={1}>\n What is in Sanity replaces whatever General Translation holds\n for that version of the document β€” including a translation that\n has finished but has not been imported yet. Import any pending\n translations before turning this on.\n </Text>\n </Stack>\n </Card>\n\n <Text size={1} muted>\n This applies to translation runs started from this Studio session.\n To send them without starting a run, use Save Local Edits.\n </Text>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","import { pluginConfig } from '../adapter/core';\nimport { version as PACKAGE_VERSION } from '../../package.json';\nimport type { Secrets } from '../types';\nimport type { TranslationPreferences } from '../adapter/types';\nimport type { TranslationSummary } from './translationSummary';\n\nexport type DebugInfo = {\n package: { name: 'gt-sanity'; version: string };\n sanity: { projectId?: string; dataset?: string };\n generalTranslation: {\n projectId?: string;\n /** Whether the secrets document supplied an API key. Never the key. */\n apiKeyConfigured: boolean;\n secretsNamespace: string;\n secretsDocumentFound: boolean;\n branchId?: string;\n };\n locales: { sourceLocale: string; targetLocales: string[] };\n documents: {\n translationLevel: string;\n translateDocuments: unknown[];\n fieldLevelDocuments: unknown[];\n languageField: string;\n singletons: string[];\n };\n fieldRules: {\n ignoreFields: unknown[];\n dedupeFields: unknown[];\n skipFields: unknown[];\n additionalStopTypes: string[];\n };\n /**\n * Where the translations actually are. A high `draftOnly` with `published`\n * at zero means they exist but are invisible to anything reading the\n * published perspective.\n */\n translations: TranslationSummary;\n /** Effective values, after any stored user choice overrides plugin config. */\n preferences: TranslationPreferences;\n customization: {\n additionalSerializers: string[];\n additionalDeserializers: string[];\n additionalBlockDeserializers: number;\n };\n};\n\nexport type BuildDebugInfoInput = {\n secrets: Secrets | null;\n preferences: TranslationPreferences;\n translations: TranslationSummary;\n sanityProjectId?: string;\n sanityDataset?: string;\n branchId?: string;\n};\n\n/**\n * Collects the plugin's effective configuration for support and bug reports.\n *\n * The API key is never included, only whether one is set β€” the result is built\n * to be pasted into a ticket. Functions and serializer implementations are\n * reduced to names and counts so the result stays JSON-serializable.\n */\nexport function buildDebugInfo({\n secrets,\n preferences,\n translations,\n sanityProjectId,\n sanityDataset,\n branchId,\n}: BuildDebugInfoInput): DebugInfo {\n const deserializers = pluginConfig.getAdditionalDeserializers();\n const deserializerTypes = deserializers?.types ?? {};\n\n return {\n package: { name: 'gt-sanity', version: PACKAGE_VERSION },\n sanity: { projectId: sanityProjectId, dataset: sanityDataset },\n generalTranslation: {\n projectId: secrets?.project,\n apiKeyConfigured: Boolean(secrets?.secret),\n secretsNamespace: pluginConfig.getSecretsNamespace(),\n secretsDocumentFound: secrets !== null,\n branchId,\n },\n locales: {\n sourceLocale: pluginConfig.getSourceLocale(),\n targetLocales: pluginConfig.getLocales(),\n },\n documents: {\n translationLevel: pluginConfig.getTranslationLevel(),\n translateDocuments: pluginConfig.getTranslateDocuments(),\n fieldLevelDocuments: pluginConfig.getFieldLevelDocuments(),\n languageField: pluginConfig.getLanguageField(),\n singletons: pluginConfig.getSingletons(),\n },\n fieldRules: {\n ignoreFields: pluginConfig.getIgnoreFields(),\n dedupeFields: pluginConfig.getDedupeFields(),\n skipFields: pluginConfig.getSkipFields(),\n additionalStopTypes: pluginConfig.getAdditionalStopTypes(),\n },\n translations,\n preferences,\n customization: {\n additionalSerializers: Object.keys(\n pluginConfig.getAdditionalSerializers()?.types ?? {}\n ),\n additionalDeserializers: Object.keys(deserializerTypes),\n additionalBlockDeserializers:\n pluginConfig.getAdditionalBlockDeserializers()?.length ?? 0,\n },\n };\n}\n\nexport function formatDebugInfo(info: DebugInfo): string {\n return JSON.stringify(info, null, 2);\n}\n","import type { SanityClient, SanityDocument } from 'sanity';\nimport { pluginConfig } from '../adapter/core';\nimport { getDocumentPublishedId } from './documentIds';\n\nexport type TranslationSummary = {\n /** Source documents the plugin is configured to translate. */\n documentsChecked: number;\n /** Source documents times target locales. */\n expected: number;\n /** Translated documents recorded in `translation.metadata`. */\n found: number;\n /** Found translations that exist only as a draft. */\n draftOnly: number;\n /** Found translations that have a published version. */\n published: number;\n /** Expected translations with no `translation.metadata` entry. */\n missing: number;\n};\n\nexport const EMPTY_TRANSLATION_SUMMARY: TranslationSummary = {\n documentsChecked: 0,\n expected: 0,\n found: 0,\n draftOnly: 0,\n published: 0,\n missing: 0,\n};\n\ntype MetadataEntry = { targets?: { language?: string; id?: string }[] };\n\nexport type SummarizeInput = {\n documentCount: number;\n targetLocaleCount: number;\n translatedIds: string[];\n publishedIds: string[];\n draftIds: string[];\n};\n\n/**\n * Counts translations by where they exist.\n *\n * A translation with no published version is only visible to a reader on the\n * drafts perspective, which is why `draftOnly` is reported separately rather\n * than folded into `found`.\n */\nexport function summarizeTranslations({\n documentCount,\n targetLocaleCount,\n translatedIds,\n publishedIds,\n draftIds,\n}: SummarizeInput): TranslationSummary {\n const unique = Array.from(new Set(translatedIds));\n const publishedSet = new Set(publishedIds);\n const draftSet = new Set(draftIds);\n\n const published = unique.filter((id) => publishedSet.has(id)).length;\n const draftOnly = unique.filter(\n (id) => !publishedSet.has(id) && draftSet.has(`drafts.${id}`)\n ).length;\n const expected = documentCount * targetLocaleCount;\n\n return {\n documentsChecked: documentCount,\n expected,\n found: unique.length,\n draftOnly,\n published,\n missing: Math.max(0, expected - unique.length),\n };\n}\n\n/**\n * Reads `translation.metadata` for the given documents and reports how many\n * translations exist, and whether they are published or draft-only.\n */\nexport async function collectTranslationSummary(\n documents: SanityDocument[],\n client: SanityClient\n): Promise<TranslationSummary> {\n const documentIds = documents.map(getDocumentPublishedId);\n const targetLocales = pluginConfig.getLocales();\n\n if (documentIds.length === 0) {\n return EMPTY_TRANSLATION_SUMMARY;\n }\n\n // Only the configured target locales are counted. Metadata can also hold\n // entries for the source and for locales dropped from the configuration\n // since, and neither is something this reports on.\n //\n // The metadata document is found by reference rather than by its\n // source-language entry: that entry records whatever `sourceLocale` was set\n // when it was created, so a project that later changed it would match none\n // of its own translations.\n const entries = await client.fetch<MetadataEntry[]>(\n `*[_type == 'translation.metadata' && references($documentIds)]{\n 'targets': translations[language in $targetLocales && defined(value._ref)]{\n language,\n 'id': value._ref\n }\n }`,\n { documentIds, targetLocales }\n );\n\n const translatedIds = entries\n .flatMap((entry) => entry.targets ?? [])\n .map((target) => target.id)\n .filter((id): id is string => Boolean(id));\n\n if (translatedIds.length === 0) {\n return summarizeTranslations({\n documentCount: documentIds.length,\n targetLocaleCount: targetLocales.length,\n translatedIds: [],\n publishedIds: [],\n draftIds: [],\n });\n }\n\n const unique = Array.from(new Set(translatedIds));\n const existence = await client.fetch<{\n publishedIds: string[];\n draftIds: string[];\n }>(\n `{\n 'publishedIds': *[_id in $ids]._id,\n 'draftIds': *[_id in $draftIds]._id\n }`,\n { ids: unique, draftIds: unique.map((id) => `drafts.${id}`) }\n );\n\n return summarizeTranslations({\n documentCount: documentIds.length,\n targetLocaleCount: targetLocales.length,\n translatedIds: unique,\n publishedIds: existence?.publishedIds ?? [],\n draftIds: existence?.draftIds ?? [],\n });\n}\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { Box, Button, Card, Dialog, Flex, Stack } from '@sanity/ui';\nimport { Code } from '@sanity/ui/code';\nimport { ClipboardIcon } from '@sanity/icons/Clipboard';\nimport { useClient } from '../../hooks/useClient';\nimport { useTranslations } from '../TranslationsProvider';\nimport { buildDebugInfo, formatDebugInfo } from '../../utils/debugInfo';\nimport {\n collectTranslationSummary,\n EMPTY_TRANSLATION_SUMMARY,\n type TranslationSummary,\n} from '../../utils/translationSummary';\n\ninterface DebugInfoDialogProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport const DebugInfoDialog: React.FC<DebugInfoDialogProps> = ({\n isOpen,\n onClose,\n}) => {\n const {\n secrets,\n documents,\n branchId,\n autoRefresh,\n autoImport,\n autoPatchReferences,\n autoPublish,\n preserveExistingTranslations,\n } = useTranslations();\n const client = useClient();\n const [copied, setCopied] = useState(false);\n const [translations, setTranslations] = useState<TranslationSummary>(\n EMPTY_TRANSLATION_SUMMARY\n );\n\n const { projectId, dataset } = client.config();\n\n const serialized = useMemo(\n () =>\n formatDebugInfo(\n buildDebugInfo({\n secrets,\n preferences: {\n autoRefresh,\n autoImport,\n autoPatchReferences,\n autoPublish,\n preserveExistingTranslations,\n },\n translations,\n sanityProjectId: projectId,\n sanityDataset: dataset,\n branchId,\n })\n ),\n [\n secrets,\n translations,\n branchId,\n projectId,\n dataset,\n autoRefresh,\n autoImport,\n autoPatchReferences,\n autoPublish,\n preserveExistingTranslations,\n ]\n );\n\n // Reads the dataset, so it runs when the dialog opens rather than on every\n // status poll. Failures leave the zeroed summary rather than blocking the\n // rest of the debug output.\n useEffect(() => {\n if (!isOpen) return;\n let cancelled = false;\n collectTranslationSummary(documents, client)\n .then((summary) => {\n if (!cancelled) setTranslations(summary);\n })\n .catch(() => {\n if (!cancelled) setTranslations(EMPTY_TRANSLATION_SUMMARY);\n });\n return () => {\n cancelled = true;\n };\n }, [isOpen, documents, client]);\n\n if (!isOpen) return null;\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(serialized);\n setCopied(true);\n } catch {\n // Clipboard unavailable (insecure origin, denied permission) β€” the text\n // is on screen and selectable.\n setCopied(false);\n }\n };\n\n return (\n <Dialog\n header='Debug info'\n id='gt-debug-info-dialog'\n onClose={onClose}\n width={2}\n footer={\n <Box padding={3}>\n <Flex gap={2} justify='space-between' align='center'>\n <Button\n icon={ClipboardIcon}\n text={copied ? 'Copied' : 'Copy'}\n tone={copied ? 'positive' : 'default'}\n mode='ghost'\n onClick={handleCopy}\n />\n <Button text='Close' mode='ghost' onClick={onClose} />\n </Flex>\n </Box>\n }\n >\n <Box padding={4}>\n <Stack gap={4}>\n <Card\n padding={3}\n radius={2}\n tone='transparent'\n border\n overflow='auto'\n style={{ maxHeight: '50vh' }}\n >\n <Code size={0} language='json'>\n {serialized}\n </Code>\n </Card>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","import { Badge, Flex, Text } from '@sanity/ui';\nimport { getLocaleDisplay } from '../../utils/localeDisplay';\n\ntype LocaleLabelProps = {\n localeId: string;\n size?: number;\n weight?: 'regular' | 'medium' | 'semibold' | 'bold';\n};\n\n/**\n * Locale display used across the plugin UI: flag emoji, plain language name,\n * and the locale code in a muted chip β€” e.g. `πŸ‡ΊπŸ‡Έ English [en-US]`.\n */\nexport const LocaleLabel = ({\n localeId,\n size = 1,\n weight = 'medium',\n}: LocaleLabelProps) => {\n const { emoji, name, code, verbatim } = getLocaleDisplay(localeId);\n\n return (\n <Flex align='center' gap={2}>\n {emoji && (\n <Text size={size} aria-hidden>\n {emoji}\n </Text>\n )}\n <Text size={size} weight={weight}>\n {name}\n </Text>\n {!verbatim && (\n <Badge fontSize={0} radius={2}>\n {code}\n </Badge>\n )}\n </Flex>\n );\n};\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { useCallback, useState } from 'react';\nimport { Badge, Box, Button, Flex, Grid, Spinner, Text } from '@sanity/ui';\nimport { CheckmarkCircleIcon } from '@sanity/icons/CheckmarkCircle';\nimport { DownloadIcon } from '@sanity/icons/Download';\nimport { LocaleLabel } from './LocaleLabel';\n\n/**\n * What a locale row can be showing.\n *\n * General Translation reports a translation as complete or not, with nothing in\n * between, so a percentage was only ever 0 or 100 β€” and 0 read identically for\n * \"never translated\" and \"being translated right now\".\n */\nexport type LanguageStatusState =\n | 'not-translated'\n | 'translating'\n | 'ready'\n | 'imported';\n\ntype LanguageStatusProps = {\n localeId: string;\n state: LanguageStatusState;\n importFile: () => Promise<void>;\n /**\n * This locale is part of an import running elsewhere, such as Import All.\n * The row's own button state only covers a click on that button, so without\n * this a bulk import leaves every row looking idle until it finishes.\n */\n isImporting?: boolean;\n};\n\nconst STATE_LABEL: Record<LanguageStatusState, string> = {\n 'not-translated': 'Not translated',\n translating: 'Translating…',\n ready: 'Ready to import',\n imported: 'Imported',\n};\n\nexport const LanguageStatus = ({\n localeId,\n state,\n importFile,\n isImporting = false,\n}: LanguageStatusProps) => {\n const [isSelfImporting, setIsSelfImporting] = useState(false);\n // A bulk import reports every queued locale at once and only clears the set\n // when the whole run ends, so a row that has already landed must stop\n // reporting itself as in progress on its own.\n const isBusy = (isSelfImporting || isImporting) && state !== 'imported';\n\n const handleImport = useCallback(async () => {\n setIsSelfImporting(true);\n try {\n await importFile();\n } finally {\n setIsSelfImporting(false);\n }\n }, [importFile]);\n\n return (\n <Grid gridTemplateColumns={5} gap={3} paddingX={3} paddingY={2}>\n <Flex gridColumnStart={1} gridColumnEnd={3} align='center'>\n <LocaleLabel localeId={localeId} />\n </Flex>\n\n <Flex gridColumnStart={3} gridColumnEnd={5} align='center' gap={2}>\n {(state === 'translating' || isBusy) && <Spinner size={1} muted />}\n <Text size={1} muted={state !== 'ready'}>\n {isBusy ? 'Importing…' : STATE_LABEL[state]}\n </Text>\n </Flex>\n\n <Flex\n gridColumnStart={5}\n gridColumnEnd={6}\n align='center'\n justify='flex-end'\n >\n {state === 'imported' ? (\n <Badge tone='positive' fontSize={0} radius={2}>\n <Flex align='center' gap={1}>\n <CheckmarkCircleIcon />\n <Box>Imported</Box>\n </Flex>\n </Badge>\n ) : (\n <Button\n style={{ width: '100%' }}\n mode='ghost'\n fontSize={1}\n padding={2}\n onClick={handleImport}\n text={isBusy ? 'Importing…' : 'Import'}\n loading={isBusy}\n icon={DownloadIcon}\n disabled={isBusy || state !== 'ready'}\n />\n )}\n </Flex>\n </Grid>\n );\n};\n","import type { LanguageStatusState } from '../components/shared/LanguageStatus';\nimport type { TranslationStatus } from '../adapter/types';\n\nexport type ResolveLanguageStatusInput = {\n status?: TranslationStatus;\n isImported: boolean;\n isPending: boolean;\n};\n\n/**\n * Resolves what a locale row shows.\n *\n * `imported` wins over everything: once a translation is in Sanity, the status\n * query stops returning it, so a later refresh reports it as not ready.\n */\nexport function resolveLanguageStatusState({\n status,\n isImported,\n isPending,\n}: ResolveLanguageStatusInput): LanguageStatusState {\n if (isImported) return 'imported';\n if (status?.isReady) return 'ready';\n if (isPending) return 'translating';\n return 'not-translated';\n}\n","import { useCallback } from 'react';\nimport { Button, Checkbox, Flex } from '@sanity/ui';\nimport { TranslationLocale } from '../../types';\nimport { LocaleLabel } from './LocaleLabel';\n\ntype LocaleCheckboxProps = {\n locale: TranslationLocale;\n toggle: (locale: string, shouldEnable: boolean) => void;\n checked: boolean;\n};\n\nexport const LocaleCheckbox = ({\n locale,\n toggle,\n checked,\n}: LocaleCheckboxProps) => {\n const onClick = useCallback(\n () => toggle(locale.localeId, !checked),\n [locale.localeId, toggle, checked]\n );\n\n return (\n <Button\n mode='ghost'\n onClick={onClick}\n style={{ cursor: 'pointer' }}\n padding={3}\n >\n <Flex align='center' gap={3}>\n <Checkbox\n style={{ pointerEvents: 'none' }}\n onChange={onClick}\n checked={checked}\n />\n <LocaleLabel localeId={locale.localeId} />\n </Flex>\n </Button>\n );\n};\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\n/**\n * Add cleanup function to cancel async tasks\n */\n\nimport { useMemo, useState, useCallback, useEffect, useRef } from 'react';\nimport { Stack, Text, Card, Button, Grid, Flex, Switch } from '@sanity/ui';\nimport { Tooltip } from '@sanity/ui/tooltip';\nimport { useToast } from '@sanity/ui/toast';\nimport { pluginConfig } from '../../adapter/core';\nimport { SaveLocalTranslationsDialog } from '../page/SaveLocalTranslationsDialog';\nimport { DebugInfoDialog } from '../page/DebugInfoDialog';\nimport { version as PACKAGE_VERSION } from '../../../package.json';\nimport { useTranslations } from '../TranslationsProvider';\nimport { LanguageStatus } from '../shared/LanguageStatus';\nimport { resolveLanguageStatusState } from '../../utils/languageStatusState';\nimport { LocaleCheckbox } from '../shared/LocaleCheckbox';\nimport { DownloadIcon } from '@sanity/icons/Download';\nimport { LinkIcon } from '@sanity/icons/Link';\nimport { PublishIcon } from '@sanity/icons/Publish';\nimport { RefreshIcon } from '@sanity/icons/Refresh';\nimport { TranslateIcon } from '@sanity/icons/Translate';\nimport { UploadIcon } from '@sanity/icons/Upload';\nimport {\n createTranslationStatusKey,\n getDocumentPublishedId,\n} from '../../utils/documentIds';\n\nexport const TranslationView = () => {\n const {\n documents,\n locales,\n translationStatuses,\n pendingTranslations,\n importingTranslations,\n branchId,\n isBusy,\n handleTranslateAll,\n handleUploadExistingTranslations,\n handleImportDocument,\n handleRefreshAll,\n isRefreshing,\n importedTranslations,\n setLocales,\n handlePatchDocumentReferences,\n handlePublishAllTranslations,\n autoRefresh,\n setAutoRefresh,\n autoImport,\n setAutoImport,\n autoPatchReferences,\n setAutoPatchReferences,\n autoPublish,\n setAutoPublish,\n preserveExistingTranslations,\n setPreserveExistingTranslations,\n getVersionId,\n } = useTranslations();\n\n const [isImporting, setIsImporting] = useState(false);\n const [isPublishing, setIsPublishing] = useState(false);\n const [isUploadingExisting, setIsUploadingExisting] = useState(false);\n const [isSaveLocalDialogOpen, setIsSaveLocalDialogOpen] = useState(false);\n const [isDebugInfoDialogOpen, setIsDebugInfoDialogOpen] = useState(false);\n\n const toast = useToast();\n\n // Get the single document (first document in single document mode)\n const document = documents[0];\n\n // Extract the current document's language from the language field\n const currentDocumentLanguage = useMemo(() => {\n if (!document) return null;\n\n // Get the language from the document's language field\n const languageField = pluginConfig.getLanguageField();\n const documentLanguage = document[languageField];\n\n // If no language field is set, assume it's the source language\n return documentLanguage || pluginConfig.getSourceLocale();\n }, [document]);\n\n // Only show translation components if we're on a source language document\n const shouldShowTranslationComponents = useMemo(() => {\n if (!currentDocumentLanguage) return false;\n return currentDocumentLanguage === pluginConfig.getSourceLocale();\n }, [currentDocumentLanguage]);\n\n // Get available locales (excluding source locale)\n const availableLocales = useMemo(() => {\n const sourceLocale = pluginConfig.getSourceLocale();\n return locales.filter(\n (locale) => locale.enabled !== false && locale.localeId !== sourceLocale\n );\n }, [locales]);\n\n // Every configured target locale, regardless of selection. The status\n // section renders this stable list so toggling locale checkboxes doesn't\n // add/remove rows and shift the layout.\n const statusLocales = useMemo(() => {\n const sourceLocale = pluginConfig.getSourceLocale();\n return locales.filter((locale) => locale.localeId !== sourceLocale);\n }, [locales]);\n\n // Get document ID for status tracking\n const documentId = useMemo(() => {\n if (!document) return null;\n return getDocumentPublishedId(document);\n }, [document]);\n\n // Version the status entries are keyed under: the _rev pinned at upload\n // time when available, so importing in place (which bumps the live _rev)\n // doesn't detach the UI from the statuses of the uploaded version.\n const versionId = useMemo(() => {\n if (!document) return null;\n return getVersionId(document);\n }, [document, getVersionId]);\n\n // Translations that were already complete when this dialog opened. Auto-import\n // means \"import a translation that finishes while I am watching\", so these are\n // left alone: importing them would rewrite translated documents β€” discarding\n // any edits made to them β€” every time the dialog is opened. Reset on Translate,\n // so a fresh run's results are imported even for a locale that already had one.\n const alreadyCompleteRef = useRef<Set<string> | null>(null);\n\n const statusKeyFor = useCallback(\n (localeId: string) =>\n createTranslationStatusKey(\n branchId,\n documentId ?? '',\n versionId ?? '',\n localeId\n ),\n [branchId, documentId, versionId]\n );\n\n if (\n alreadyCompleteRef.current === null &&\n documentId &&\n versionId &&\n translationStatuses.size > 0\n ) {\n alreadyCompleteRef.current = new Set(\n statusLocales\n .map((locale) => statusKeyFor(locale.localeId))\n .filter((key) => translationStatuses.get(key)?.isReady)\n );\n }\n\n // The per-locale rows already read \"Translating…\"; this only guards the\n // button against enqueueing the same run twice.\n const isWaitingOnTranslations = statusLocales.some((locale) =>\n pendingTranslations.has(statusKeyFor(locale.localeId))\n );\n\n // Unified import functionality\n const handleImportTranslations = useCallback(\n async (options: { autoOnly?: boolean } = {}) => {\n const { autoOnly = false } = options;\n\n // Check preconditions\n if (isImporting || !documentId || !versionId) return;\n if (autoOnly && !autoImport) return;\n\n // Find translations ready to import (any configured locale, not just\n // the ones currently selected for translation)\n const readyTranslations = statusLocales.filter((locale) => {\n const key = createTranslationStatusKey(\n branchId,\n documentId,\n versionId,\n locale.localeId\n );\n const status = translationStatuses.get(key);\n if (!status?.isReady || importedTranslations.has(key)) return false;\n return !(autoOnly && alreadyCompleteRef.current?.has(key));\n });\n\n if (readyTranslations.length === 0) return;\n\n setIsImporting(true);\n try {\n // Import sequentially: internationalized-array imports patch this same\n // document in place, so concurrent locale imports would overwrite each\n // other and only the last locale would survive.\n for (const locale of readyTranslations) {\n await handleImportDocument(documentId, versionId, locale.localeId);\n }\n\n // Auto patch document references if enabled\n if (autoPatchReferences) {\n await handlePatchDocumentReferences();\n }\n\n // Auto publish translations if enabled\n if (autoPublish) {\n await handlePublishAllTranslations();\n }\n } finally {\n setIsImporting(false);\n }\n },\n [\n autoImport,\n isImporting,\n documentId,\n versionId,\n statusLocales,\n translationStatuses,\n importedTranslations,\n handleImportDocument,\n autoPatchReferences,\n handlePatchDocumentReferences,\n autoPublish,\n handlePublishAllTranslations,\n toast,\n ]\n );\n\n // Check for completed translations on status updates (auto-import)\n useEffect(() => {\n handleImportTranslations({ autoOnly: true });\n }, [handleImportTranslations]);\n\n // Locale toggle functionality\n const toggleLocale = useCallback(\n (localeId: string, shouldEnable: boolean) => {\n const updatedLocales = locales.map((locale) =>\n locale.localeId === localeId\n ? { ...locale, enabled: shouldEnable }\n : locale\n );\n setLocales(updatedLocales);\n },\n [locales, setLocales]\n );\n\n const toggleAllLocales = useCallback(() => {\n const sourceLocale = pluginConfig.getSourceLocale();\n const nonSourceLocales = locales.filter(\n (locale) => locale.localeId !== sourceLocale\n );\n const allEnabled = nonSourceLocales.every(\n (locale) => locale.enabled === true || locale.enabled === undefined\n );\n\n const updatedLocales = locales.map((locale) =>\n locale.localeId === sourceLocale\n ? locale // Don't change source locale\n : { ...locale, enabled: !allEnabled }\n );\n setLocales(updatedLocales);\n }, [locales, setLocales]);\n\n // Show message if we're not on a source language document\n if (!shouldShowTranslationComponents) {\n return (\n <Card padding={4} tone='neutral' border>\n <Text size={1} muted>\n Translation tools are only available for{' '}\n <code>{pluginConfig.getSourceLocale()}</code> documents.\n </Text>\n </Card>\n );\n }\n\n return (\n <Stack gap={6} padding={4}>\n {/* Translate Section */}\n <Stack gap={4}>\n <Text as='h2' weight='semibold' size={2}>\n Translate\n </Text>\n\n {/* Locale Selection */}\n <Stack gap={3}>\n <Flex align='center' justify='space-between'>\n <Text weight='semibold' size={1}>\n {availableLocales.length === 1\n ? 'Select locale'\n : 'Select locales'}\n </Text>\n <Button\n fontSize={1}\n padding={2}\n mode='ghost'\n text='Toggle All'\n onClick={toggleAllLocales}\n />\n </Flex>\n\n <Grid gridTemplateColumns={[1, 1, 2, 3]} gap={1}>\n {locales\n .filter(\n (locale) => locale.localeId !== pluginConfig.getSourceLocale()\n )\n .map((locale) => (\n <LocaleCheckbox\n key={locale.localeId}\n locale={locale}\n toggle={toggleLocale}\n checked={\n locale.enabled === true || locale.enabled === undefined\n }\n />\n ))}\n </Grid>\n </Stack>\n\n <Button\n onClick={() => {\n // A new run's results should import even for locales that already\n // had a translation when the dialog opened.\n alreadyCompleteRef.current = new Set();\n handleTranslateAll();\n }}\n disabled={\n isBusy || isWaitingOnTranslations || !availableLocales.length\n }\n icon={TranslateIcon}\n text={isWaitingOnTranslations ? 'Translating…' : 'Translate'}\n loading={(isBusy && !isUploadingExisting) || isWaitingOnTranslations}\n />\n </Stack>\n\n <SaveLocalTranslationsDialog\n isOpen={isSaveLocalDialogOpen}\n onClose={() => setIsSaveLocalDialogOpen(false)}\n onConfirm={() => {\n setPreserveExistingTranslations(true);\n setIsSaveLocalDialogOpen(false);\n }}\n />\n\n {/* Translation Status Section */}\n {documentId && versionId && statusLocales.length > 0 && (\n <Stack gap={4}>\n <Flex align='center' justify='space-between'>\n <Text as='h2' weight='semibold' size={2}>\n Translation Status\n </Text>\n <Flex gap={3} align='center'>\n <Flex gap={2} align='center'>\n <Text size={1}>Auto-refresh</Text>\n <Switch\n checked={autoRefresh}\n onChange={() => setAutoRefresh(!autoRefresh)}\n />\n </Flex>\n <Button\n fontSize={1}\n padding={2}\n mode='ghost'\n icon={RefreshIcon}\n text='Refresh'\n loading={isRefreshing}\n onClick={() => handleRefreshAll()}\n disabled={isRefreshing || isBusy}\n />\n </Flex>\n </Flex>\n\n <Card border radius={3} paddingY={1}>\n {statusLocales.map((locale) => {\n const key = createTranslationStatusKey(\n branchId,\n documentId,\n versionId,\n locale.localeId\n );\n const status = translationStatuses.get(key);\n const isImported = importedTranslations.has(key);\n\n return (\n <LanguageStatus\n key={key}\n localeId={locale.localeId}\n state={resolveLanguageStatusState({\n status,\n isImported,\n isPending: pendingTranslations.has(key),\n })}\n isImporting={importingTranslations.has(key)}\n importFile={async () => {\n if (!isImported && status?.isReady) {\n await handleImportDocument(\n documentId,\n versionId,\n locale.localeId\n );\n }\n }}\n />\n );\n })}\n </Card>\n\n {/* Import Controls */}\n <Stack gap={3}>\n <Flex gap={2} align='center' justify='flex-start'>\n <Button\n mode='ghost'\n onClick={async () => {\n setIsUploadingExisting(true);\n try {\n await handleUploadExistingTranslations();\n } finally {\n setIsUploadingExisting(false);\n }\n }}\n disabled={isBusy || !availableLocales.length}\n icon={UploadIcon}\n text='Save Local Edits'\n loading={isUploadingExisting}\n style={{ minWidth: '180px' }}\n />\n <Flex gap={2} align='center'>\n <Switch\n checked={preserveExistingTranslations}\n onChange={() => {\n // Turning it on changes what wins on a conflict, so explain\n // before enabling; turning it off is safe.\n if (preserveExistingTranslations) {\n setPreserveExistingTranslations(false);\n } else {\n setIsSaveLocalDialogOpen(true);\n }\n }}\n />\n <Text size={1}>Save local edits before translating</Text>\n </Flex>\n </Flex>\n <Flex gap={3} align='center' justify='space-between'>\n <Flex gap={2} align='center'>\n <Button\n mode='ghost'\n onClick={() => handleImportTranslations()}\n text='Import All'\n loading={isImporting}\n icon={DownloadIcon}\n disabled={\n isImporting ||\n statusLocales.every((locale) => {\n const key = createTranslationStatusKey(\n branchId,\n documentId,\n versionId,\n locale.localeId\n );\n const status = translationStatuses.get(key);\n return !status?.isReady || importedTranslations.has(key);\n })\n }\n style={{ minWidth: '180px' }}\n />\n <Flex gap={2} align='center'>\n <Switch\n checked={autoImport}\n onChange={() => setAutoImport(!autoImport)}\n disabled={isImporting}\n />\n <Text size={1}>Auto-import when complete</Text>\n </Flex>\n </Flex>\n {/* Counted against every configured locale. The number of\n currently-ready translations decays to zero as they are\n imported, because a downloaded file drops out of the status\n query β€” which made the old denominator read \"6/0\". */}\n <Text size={1} muted>\n {\n statusLocales.filter((locale) =>\n importedTranslations.has(statusKeyFor(locale.localeId))\n ).length\n }{' '}\n of {statusLocales.length} imported\n </Text>\n </Flex>\n\n <Flex gap={2} align='center' justify='flex-start'>\n <Tooltip\n placement='top'\n content={`Replaces references to ${pluginConfig.getSourceLocale()} documents in this document with the corresponding translated document reference`}\n >\n <Button\n mode='ghost'\n onClick={async () => {\n await handlePatchDocumentReferences();\n }}\n text='Patch References'\n loading={isBusy}\n icon={LinkIcon}\n disabled={isBusy || isImporting}\n style={{ minWidth: '180px' }}\n />\n </Tooltip>\n <Flex gap={2} align='center'>\n <Switch\n checked={autoPatchReferences}\n onChange={() => setAutoPatchReferences(!autoPatchReferences)}\n disabled={isImporting || isBusy}\n />\n <Text size={1}>Auto-patch after import</Text>\n </Flex>\n </Flex>\n\n <Flex gap={2} align='center' justify='flex-start'>\n <Tooltip\n placement='top'\n content='Publishes all translations (if the source document is published)'\n >\n <Button\n mode='ghost'\n onClick={async () => {\n setIsPublishing(true);\n try {\n await handlePublishAllTranslations();\n } finally {\n setIsPublishing(false);\n }\n }}\n text='Publish Translations'\n loading={isPublishing}\n icon={PublishIcon}\n disabled={isBusy || isPublishing || isImporting}\n style={{ minWidth: '180px' }}\n />\n </Tooltip>\n <Flex gap={2} align='center'>\n <Switch\n checked={autoPublish}\n onChange={() => setAutoPublish(!autoPublish)}\n disabled={isPublishing || isImporting || isBusy}\n />\n <Text size={1}>Auto-publish after import</Text>\n </Flex>\n </Flex>\n </Stack>\n </Stack>\n )}\n\n <Card borderTop paddingTop={3}>\n <Flex align='center' justify='flex-end' gap={2}>\n <Text size={1} muted>\n gt-sanity v{PACKAGE_VERSION}\n </Text>\n <Button\n fontSize={1}\n padding={2}\n mode='bleed'\n text='Debug info'\n onClick={() => setIsDebugInfoDialogOpen(true)}\n />\n </Flex>\n </Card>\n\n <DebugInfoDialog\n isOpen={isDebugInfoDialogOpen}\n onClose={() => setIsDebugInfoDialogOpen(false)}\n />\n </Stack>\n );\n};\n","import React, { useState } from 'react';\nimport { DocumentActionComponent } from 'sanity';\nimport { TranslateIcon } from '@sanity/icons/Translate';\nimport { BaseTranslationWrapper } from '../components/shared/BaseTranslationWrapper';\nimport { TranslationsProvider } from '../components/TranslationsProvider';\nimport { TranslationView } from '../components/tab/TranslationView';\n\nexport const translateAction: DocumentActionComponent = (props) => {\n const [dialogOpen, setDialogOpen] = useState(false);\n const document = props.draft || props.published;\n\n return {\n label: 'Translate',\n icon: TranslateIcon,\n tone: 'primary',\n onHandle: () => setDialogOpen(true),\n dialog: dialogOpen\n ? {\n type: 'dialog' as const,\n header: 'Translations',\n onClose: () => setDialogOpen(false),\n content: (\n <BaseTranslationWrapper showContainer={false}>\n <TranslationsProvider singleDocument={document}>\n <TranslationView />\n </TranslationsProvider>\n </BaseTranslationWrapper>\n ),\n }\n : null,\n };\n};\n","import { getLocaleProperties } from 'generaltranslation';\nimport type { CustomMapping } from 'generaltranslation/types';\nimport { formatLocalePropertiesLabel } from '../utils/localeDisplay';\nimport type { PluginOptions } from 'sanity';\nimport { internationalizedArray } from 'sanity-plugin-internationalized-array';\nimport type { PluginConfig as InternationalizedArrayPluginConfig } from 'sanity-plugin-internationalized-array';\n\n/**\n * A localizable field type, passed through to\n * `sanity-plugin-internationalized-array`. Built-in shortcuts:\n * - `'string'` / `'text'` (or any Sanity type name) wrap that type.\n * - `'block'` wraps a Portable Text array (`array` of `block`).\n * - An object form supplies a field definition verbatim; the generated type is\n * named `internationalizedArray<Name>`.\n */\nexport type FieldLevelFieldType =\n | string\n | {\n /** Suffix used in the generated type name, e.g. `seo` β†’ `internationalizedArraySeo`. */\n name: string;\n /** Sanity type of the wrapped field (e.g. an object type name). */\n type: string;\n title?: string;\n of?: unknown[];\n fields?: unknown[];\n options?: Record<string, unknown>;\n };\n\n/**\n * Field-level localization options. `gtPlugin` forwards these to\n * `sanity-plugin-internationalized-array` β€” the reference Sanity plugin, which\n * gt-sanity configures rather than reimplements β€” keeping `sourceLocale` /\n * `locales` from `gtPlugin()` as the only source of locale identity.\n */\nexport type GTFieldLevelLocalizationConfig = {\n /** Register `internationalizedArray*` schema types + Studio UI. Default `false`. */\n enabled?: boolean;\n /** Which field types to wrap. Default `['string', 'text']`. */\n fieldTypes?: FieldLevelFieldType[];\n /** Per-locale display labels shown in the Studio input. */\n languageTitles?: Record<string, string>;\n /** Compute a display label for a locale (overrides `languageTitles`). */\n getLanguageTitle?: (locale: string) => string;\n /**\n * Locales pre-populated on empty localized fields.\n * Default: the plugin's source locale.\n */\n defaultLanguages?: string[];\n /** Passed through to `sanity-plugin-internationalized-array`. */\n apiVersion?: InternationalizedArrayPluginConfig['apiVersion'];\n /** Passed through to `sanity-plugin-internationalized-array`. */\n buttonLocations?: InternationalizedArrayPluginConfig['buttonLocations'];\n /** Passed through to `sanity-plugin-internationalized-array`. */\n buttonAddAll?: InternationalizedArrayPluginConfig['buttonAddAll'];\n /** Passed through to `sanity-plugin-internationalized-array`. */\n languageDisplay?: InternationalizedArrayPluginConfig['languageDisplay'];\n};\n\nexport type ResolvedFieldLevelConfig = Required<\n Pick<GTFieldLevelLocalizationConfig, 'enabled' | 'fieldTypes'>\n> &\n GTFieldLevelLocalizationConfig;\n\nexport function resolveFieldLevelConfig(\n config: GTFieldLevelLocalizationConfig | undefined\n): ResolvedFieldLevelConfig {\n return {\n enabled: false,\n fieldTypes: ['string', 'text'],\n ...config,\n };\n}\n\n/** Map a GT field-type shortcut to the native plugin's `fieldTypes` entry. */\nfunction toNativeFieldType(\n fieldType: FieldLevelFieldType\n): InternationalizedArrayPluginConfig['fieldTypes'][number] {\n if (fieldType === 'block') {\n return {\n name: 'block',\n type: 'array',\n of: [{ type: 'block' }],\n } as unknown as InternationalizedArrayPluginConfig['fieldTypes'][number];\n }\n return fieldType as InternationalizedArrayPluginConfig['fieldTypes'][number];\n}\n\n/**\n * Configure `sanity-plugin-internationalized-array` from gtPlugin locale\n * config. The native plugin owns the `internationalizedArray*` schema types\n * and the Studio UI; gt-sanity only reads and writes the stored\n * `{ _key, _type, language, value }` data during translation.\n */\nexport function buildInternationalizedArrayPlugin(\n config: ResolvedFieldLevelConfig,\n sourceLocale: string,\n locales: string[],\n customMapping?: CustomMapping\n): PluginOptions {\n const languageTitle = (locale: string) =>\n config.getLanguageTitle?.(locale) ??\n config.languageTitles?.[locale] ??\n formatLocalePropertiesLabel(\n locale,\n getLocaleProperties(locale, sourceLocale, customMapping),\n customMapping?.[locale]\n );\n\n const allLocales = Array.from(new Set([sourceLocale, ...locales]));\n\n return internationalizedArray({\n languages: allLocales.map((id) => ({ id, title: languageTitle(id) })),\n defaultLanguages: config.defaultLanguages ?? [sourceLocale],\n fieldTypes: config.fieldTypes.map(toNativeFieldType),\n ...(config.apiVersion !== undefined && { apiVersion: config.apiVersion }),\n ...(config.buttonLocations !== undefined && {\n buttonLocations: config.buttonLocations,\n }),\n ...(config.buttonAddAll !== undefined && {\n buttonAddAll: config.buttonAddAll,\n }),\n ...(config.languageDisplay !== undefined && {\n languageDisplay: config.languageDisplay,\n }),\n });\n}\n","import React from 'react';\nimport { Badge, Box, Card, Flex, Spinner, Stack, Text } from '@sanity/ui';\nimport { Preview, useSchema, type SanityDocument } from 'sanity';\nimport { useIntentLink } from 'sanity/router';\nimport { LanguageStatus } from '../shared/LanguageStatus';\nimport { resolveLanguageStatusState } from '../../utils/languageStatusState';\nimport { useTranslations } from '../TranslationsProvider';\nimport {\n createTranslationStatusKey,\n getDocumentPublishedId,\n} from '../../utils/documentIds';\n\nconst DocumentRow: React.FC<{ document: SanityDocument }> = ({ document }) => {\n const {\n locales,\n translationStatuses,\n pendingTranslations,\n importingTranslations,\n downloadStatus,\n importedTranslations,\n handleImportDocument,\n branchId,\n getVersionId,\n } = useTranslations();\n\n const schema = useSchema();\n const schemaType = schema.get(document._type);\n const publishedId = getDocumentPublishedId(document);\n\n const editLink = useIntentLink({\n intent: 'edit',\n params: { id: publishedId, type: document._type },\n });\n\n const enabledLocales = locales.filter((locale) => locale.enabled !== false);\n\n return (\n <Card border radius={3} overflow='hidden'>\n <Card\n as='a'\n href={editLink.href}\n onClick={editLink.onClick}\n padding={2}\n radius={0}\n borderBottom\n style={{ textDecoration: 'none', color: 'inherit' }}\n title='Open document'\n >\n <Flex align='center' gap={3}>\n <Box flex={1}>\n {schemaType ? (\n <Preview value={document} schemaType={schemaType} />\n ) : (\n <Text weight='semibold' size={1}>\n {publishedId}\n </Text>\n )}\n </Box>\n <Badge fontSize={0} radius={2}>\n {schemaType?.title ?? document._type}\n </Badge>\n </Flex>\n </Card>\n\n <Box paddingY={1}>\n {enabledLocales.length > 0 ? (\n <Stack gap={1}>\n {enabledLocales.map((locale) => {\n const versionId = getVersionId(document);\n const key = createTranslationStatusKey(\n branchId,\n publishedId,\n versionId,\n locale.localeId\n );\n const status = translationStatuses.get(key);\n const isDownloaded = downloadStatus.downloaded.has(key);\n const isImported = importedTranslations.has(key);\n\n return (\n <LanguageStatus\n key={`${document._id}-${versionId}-${locale.localeId}`}\n localeId={locale.localeId}\n state={resolveLanguageStatusState({\n status,\n isImported: isImported || isDownloaded,\n isPending: pendingTranslations.has(key),\n })}\n isImporting={importingTranslations.has(key)}\n importFile={async () => {\n await handleImportDocument(\n publishedId,\n versionId,\n locale.localeId\n );\n }}\n />\n );\n })}\n </Stack>\n ) : (\n <Box padding={3}>\n <Text size={1} muted>\n No locales configured\n </Text>\n </Box>\n )}\n </Box>\n </Card>\n );\n};\n\nexport const TranslationsTable: React.FC = () => {\n const { documents, loadingDocuments } = useTranslations();\n\n if (loadingDocuments) {\n return (\n <Flex align='center' justify='center' padding={4}>\n <Spinner />\n </Flex>\n );\n }\n\n return (\n <Box style={{ maxHeight: '60vh', overflowY: 'auto' }}>\n <Stack gap={2}>\n {documents.map((document) => (\n <DocumentRow key={document._id} document={document} />\n ))}\n </Stack>\n </Box>\n );\n};\n","import React, { useState } from 'react';\nimport {\n Box,\n Button,\n Card,\n Checkbox,\n Dialog,\n Flex,\n Stack,\n Text,\n} from '@sanity/ui';\nimport { useTranslations } from '../TranslationsProvider';\n\ninterface TranslateAllDialogProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport const TranslateAllDialog: React.FC<TranslateAllDialogProps> = ({\n isOpen,\n onClose,\n}) => {\n const { documents, handleTranslateAll } = useTranslations();\n const [force, setForce] = useState(false);\n\n const handleConfirm = async () => {\n onClose();\n setForce(false);\n await handleTranslateAll({ force });\n };\n\n const handleCancel = () => {\n setForce(false);\n onClose();\n };\n\n if (!isOpen) return null;\n\n return (\n <Dialog\n header='Confirm Translation'\n id='translate-all-dialog'\n onClose={handleCancel}\n footer={\n <Box padding={3}>\n <Flex gap={2}>\n <Button text='Cancel' mode='ghost' onClick={handleCancel} />\n <Button\n text={force ? 'Retranslate All' : 'Translate All'}\n tone={force ? 'caution' : 'default'}\n onClick={handleConfirm}\n />\n </Flex>\n </Box>\n }\n >\n <Box padding={4}>\n <Stack gap={4}>\n <Stack gap={3}>\n <Text>\n Are you sure you want to create translations for all{' '}\n {documents.length} documents?\n </Text>\n <Text size={1} muted>\n This will submit all documents to General Translation for\n processing.\n </Text>\n </Stack>\n\n <Card\n padding={3}\n radius={2}\n tone={force ? 'caution' : 'transparent'}\n border\n >\n <Flex align='flex-start' gap={3}>\n <Checkbox\n id='translate-all-force'\n checked={force}\n onChange={(event: React.ChangeEvent<HTMLInputElement>) =>\n setForce(event.currentTarget.checked)\n }\n />\n <Stack gap={2} flex={1}>\n <Text size={1} weight='medium'>\n <label htmlFor='translate-all-force'>\n Retranslate from scratch\n </label>\n </Text>\n <Text size={1} muted>\n {force\n ? 'Existing translations will be discarded and regenerated. Edits made to translated documents will be lost.'\n : 'Leave unchecked to reuse existing translations, including edits made to translated documents in the Studio.'}\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","import React from 'react';\nimport { Box, Button, Dialog, Flex, Stack, Text } from '@sanity/ui';\nimport { useTranslations } from '../TranslationsProvider';\n\ninterface ImportAllDialogProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport const ImportAllDialog: React.FC<ImportAllDialogProps> = ({\n isOpen,\n onClose,\n}) => {\n const { documents, handleImportAll } = useTranslations();\n\n const handleConfirm = async () => {\n onClose();\n await handleImportAll();\n };\n\n if (!isOpen) return null;\n\n return (\n <Dialog\n header='Confirm Import'\n id='import-all-dialog'\n onClose={onClose}\n footer={\n <Box padding={3}>\n <Flex gap={2}>\n <Button text='Cancel' mode='ghost' onClick={onClose} />\n <Button text='Import All' tone='caution' onClick={handleConfirm} />\n </Flex>\n </Box>\n }\n >\n <Box padding={4}>\n <Stack gap={3}>\n <Text>\n Are you sure you want to import translations for all{' '}\n {documents.length} documents?\n </Text>\n <Text size={1} muted>\n This will download and apply translated content to your documents.\n Note that this will overwrite any existing translations!\n </Text>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","import React from 'react';\nimport { Box, Button, Dialog, Flex, Stack, Text } from '@sanity/ui';\nimport { useTranslations } from '../TranslationsProvider';\n\ninterface ImportMissingDialogProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport const ImportMissingDialog: React.FC<ImportMissingDialogProps> = ({\n isOpen,\n onClose,\n}) => {\n const { handleImportMissing } = useTranslations();\n\n const handleConfirm = async () => {\n onClose();\n await handleImportMissing();\n };\n\n if (!isOpen) return null;\n\n return (\n <Dialog\n header='Confirm Import Missing'\n id='import-missing-dialog'\n onClose={onClose}\n footer={\n <Box padding={3}>\n <Flex gap={2}>\n <Button text='Cancel' mode='ghost' onClick={onClose} />\n <Button text='Import Missing' onClick={handleConfirm} />\n </Flex>\n </Box>\n }\n >\n <Box padding={4}>\n <Stack gap={3}>\n <Text>\n Import only the missing translations (translations that are ready\n but haven't been imported to Sanity yet)?\n </Text>\n <Text size={1} muted>\n This will check existing translation metadata and only import\n translations that don't already exist in your dataset.\n </Text>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","import React from 'react';\nimport { Box, Button, Dialog, Flex, Stack, Text } from '@sanity/ui';\nimport { useTranslations } from '../TranslationsProvider';\n\ninterface UploadExistingDialogProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport const UploadExistingDialog: React.FC<UploadExistingDialogProps> = ({\n isOpen,\n onClose,\n}) => {\n const { documents, handleUploadExistingTranslations } = useTranslations();\n\n const handleConfirm = async () => {\n onClose();\n await handleUploadExistingTranslations();\n };\n\n if (!isOpen) return null;\n\n return (\n <Dialog\n header='Save local edits'\n id='upload-existing-dialog'\n onClose={onClose}\n footer={\n <Box padding={3}>\n <Flex gap={2}>\n <Button text='Cancel' mode='ghost' onClick={onClose} />\n <Button text='Save Local Edits' onClick={handleConfirm} />\n </Flex>\n </Box>\n }\n >\n <Box padding={4}>\n <Stack gap={3}>\n <Text>\n Save the translations currently in Sanity for all {documents.length}{' '}\n documents to General Translation?\n </Text>\n <Text size={1} muted>\n They become the stored translation for each locale, so later\n translation runs reuse them. Anything General Translation already\n holds for those versions is replaced. No translation is started.\n </Text>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","import React from 'react';\nimport { Flex, Text, Spinner } from '@sanity/ui';\n\ninterface BatchProgressProps {\n isActive: boolean;\n current: number;\n total: number;\n operationName: string;\n}\n\nexport const BatchProgress: React.FC<BatchProgressProps> = ({\n isActive,\n current,\n total,\n operationName,\n}) => {\n if (!isActive) return null;\n\n return (\n <Flex justify='center' align='center' gap={3}>\n <Spinner size={1} />\n <Text size={1}>\n {operationName} {current} of {total}...\n </Text>\n </Flex>\n );\n};\n","import React, { useState } from 'react';\nimport {\n Badge,\n Box,\n Button,\n Card,\n Container,\n Flex,\n Heading,\n Stack,\n Switch,\n Text,\n} from '@sanity/ui';\nimport { Tooltip } from '@sanity/ui/tooltip';\nimport { CheckmarkCircleIcon } from '@sanity/icons/CheckmarkCircle';\nimport { DownloadIcon } from '@sanity/icons/Download';\nimport { LinkIcon } from '@sanity/icons/Link';\nimport { PublishIcon } from '@sanity/icons/Publish';\nimport { RefreshIcon } from '@sanity/icons/Refresh';\nimport { TranslateIcon } from '@sanity/icons/Translate';\nimport { UploadIcon } from '@sanity/icons/Upload';\nimport { Link } from 'sanity/router';\nimport { BaseTranslationWrapper } from '../shared/BaseTranslationWrapper';\nimport { TranslationsProvider, useTranslations } from '../TranslationsProvider';\nimport { TranslationsTable } from './TranslationsTable';\nimport { TranslateAllDialog } from './TranslateAllDialog';\nimport { ImportAllDialog } from './ImportAllDialog';\nimport { ImportMissingDialog } from './ImportMissingDialog';\nimport { UploadExistingDialog } from './UploadExistingDialog';\nimport { SaveLocalTranslationsDialog } from './SaveLocalTranslationsDialog';\nimport { DebugInfoDialog } from './DebugInfoDialog';\nimport { BatchProgress } from './BatchProgress';\nimport { version as PACKAGE_VERSION } from '../../../package.json';\n\nconst TranslationsToolContent: React.FC = () => {\n const [isTranslateAllDialogOpen, setIsTranslateAllDialogOpen] =\n useState(false);\n const [isImportAllDialogOpen, setIsImportAllDialogOpen] = useState(false);\n const [isImportMissingDialogOpen, setIsImportMissingDialogOpen] =\n useState(false);\n const [isUploadExistingDialogOpen, setIsUploadExistingDialogOpen] =\n useState(false);\n const [isSaveLocalDialogOpen, setIsSaveLocalDialogOpen] = useState(false);\n const [isDebugInfoDialogOpen, setIsDebugInfoDialogOpen] = useState(false);\n\n const {\n isBusy,\n documents,\n locales,\n autoRefresh,\n loadingDocuments,\n importProgress,\n importedTranslations,\n pendingTranslations,\n isRefreshing,\n setAutoRefresh,\n preserveExistingTranslations,\n setPreserveExistingTranslations,\n handleRefreshAll,\n handlePatchDocumentReferences,\n handlePublishAllTranslations,\n } = useTranslations();\n\n // Track which specific operation is running\n const [currentOperation, setCurrentOperation] = useState<string | null>(null);\n\n const getProgressOperationName = () => {\n switch (currentOperation) {\n case 'Import All':\n return 'Importing';\n case 'Import Missing':\n return 'Importing missing';\n case 'Save Local Edits':\n return 'Uploading existing';\n case 'Patch References':\n return 'Patching';\n case 'Publish Translations':\n return 'Publishing';\n default:\n return 'Processing';\n }\n };\n\n // Reset current operation when operation completes\n React.useEffect(() => {\n if (!isBusy && !importProgress.isImporting) {\n setCurrentOperation(null);\n }\n }, [isBusy, importProgress.isImporting]);\n\n // A translation run stays in flight after the request resolves, so `isBusy`\n // alone drops the button back to idle while work is still happening. The\n // per-locale rows already read \"Translating…\"; this keeps the top-level\n // button honest and guards against enqueueing the same run twice.\n const isWaitingOnTranslations = pendingTranslations.size > 0;\n\n const enabledLocaleCount = locales.filter((l) => l.enabled !== false).length;\n const totalTranslations = documents.length * enabledLocaleCount;\n const actionsDisabled = isBusy || loadingDocuments || documents.length === 0;\n\n return (\n <Container width={2}>\n <Box padding={4} marginTop={5}>\n <Stack gap={5}>\n <Flex align='flex-start' justify='space-between' gap={4}>\n <Stack gap={3}>\n <Heading as='h2' size={3}>\n Translations\n </Heading>\n <Text size={1} muted>\n Manage your document translations from this centralized\n location.\n </Text>\n </Stack>\n\n <Button\n icon={TranslateIcon}\n text={isWaitingOnTranslations ? 'Translating…' : 'Translate All'}\n loading={\n (isBusy && currentOperation === 'Translate All') ||\n isWaitingOnTranslations\n }\n onClick={() => {\n setCurrentOperation('Translate All');\n setIsTranslateAllDialogOpen(true);\n }}\n disabled={actionsDisabled || isWaitingOnTranslations}\n />\n </Flex>\n\n <Stack gap={3}>\n <Flex align='center' justify='space-between' gap={3}>\n <Text size={1} muted>\n {loadingDocuments\n ? 'Loading documents...'\n : `${documents.length} ${\n documents.length === 1 ? 'document' : 'documents'\n } available for translation`}\n </Text>\n\n <Flex gap={3} align='center'>\n <Flex gap={2} align='center'>\n <Text size={1} muted>\n Save local edits\n </Text>\n <Switch\n checked={preserveExistingTranslations}\n onChange={() => {\n // Turning it on changes what wins on a conflict, so\n // explain before enabling; turning it off is safe.\n if (preserveExistingTranslations) {\n setPreserveExistingTranslations(false);\n } else {\n setIsSaveLocalDialogOpen(true);\n }\n }}\n />\n </Flex>\n <Flex gap={2} align='center'>\n <Text size={1} muted>\n Auto-refresh\n </Text>\n <Switch\n checked={autoRefresh}\n onChange={() => setAutoRefresh(!autoRefresh)}\n />\n </Flex>\n <Button\n fontSize={1}\n padding={2}\n mode='ghost'\n icon={RefreshIcon}\n text='Refresh'\n loading={isRefreshing}\n onClick={() => handleRefreshAll()}\n disabled={isRefreshing || actionsDisabled}\n />\n </Flex>\n </Flex>\n\n <TranslationsTable />\n </Stack>\n\n <Stack gap={3}>\n <Flex gap={2} align='center' justify='space-between'>\n <Flex gap={2} align='center' wrap='wrap'>\n <Tooltip\n placement='top'\n content='Imports and overrides all translations'\n >\n <Button\n mode='ghost'\n fontSize={1}\n onClick={() => {\n setCurrentOperation('Import All');\n setIsImportAllDialogOpen(true);\n }}\n text='Import All'\n loading={isBusy && currentOperation === 'Import All'}\n icon={DownloadIcon}\n disabled={actionsDisabled}\n />\n </Tooltip>\n <Tooltip\n placement='top'\n content=\"Imports all translations that are not yet imported (according to the source document's translation.metadata document)\"\n >\n <Button\n mode='ghost'\n fontSize={1}\n onClick={() => {\n setCurrentOperation('Import Missing');\n setIsImportMissingDialogOpen(true);\n }}\n text='Import Missing'\n loading={isBusy && currentOperation === 'Import Missing'}\n icon={DownloadIcon}\n disabled={actionsDisabled}\n />\n </Tooltip>\n <Tooltip\n placement='top'\n content='Uploads the translations already in Sanity to General Translation, preserving human edits'\n >\n <Button\n mode='ghost'\n fontSize={1}\n onClick={() => {\n setCurrentOperation('Save Local Edits');\n setIsUploadExistingDialogOpen(true);\n }}\n text='Save Local Edits'\n loading={isBusy && currentOperation === 'Save Local Edits'}\n icon={UploadIcon}\n disabled={actionsDisabled}\n />\n </Tooltip>\n <Tooltip\n placement='top'\n content='Replaces references in documents with the corresponding translated document reference'\n >\n <Button\n mode='ghost'\n fontSize={1}\n onClick={() => {\n setCurrentOperation('Patch References');\n handlePatchDocumentReferences();\n }}\n text='Patch References'\n loading={isBusy && currentOperation === 'Patch References'}\n icon={LinkIcon}\n disabled={actionsDisabled}\n />\n </Tooltip>\n <Tooltip\n placement='top'\n content='Publishes all translations whose source document is published'\n >\n <Button\n mode='ghost'\n fontSize={1}\n onClick={() => {\n setCurrentOperation('Publish Translations');\n handlePublishAllTranslations();\n }}\n text='Publish Translations'\n loading={\n isBusy && currentOperation === 'Publish Translations'\n }\n icon={PublishIcon}\n disabled={actionsDisabled}\n />\n </Tooltip>\n </Flex>\n\n {totalTranslations > 0 &&\n importedTranslations.size === totalTranslations && (\n <Badge tone='positive' fontSize={0} radius={2}>\n <Flex align='center' gap={1}>\n <CheckmarkCircleIcon />\n <Box>All translations imported</Box>\n </Flex>\n </Badge>\n )}\n {importedTranslations.size > 0 &&\n importedTranslations.size < totalTranslations && (\n <Text size={1} muted>\n {importedTranslations.size}/{totalTranslations} imported\n </Text>\n )}\n </Flex>\n\n <BatchProgress\n isActive={importProgress.isImporting}\n current={importProgress.current}\n total={importProgress.total}\n operationName={getProgressOperationName()}\n />\n </Stack>\n\n <Card borderTop paddingTop={4}>\n <Flex align='center' justify='space-between' gap={3} wrap='wrap'>\n <Text size={1} muted>\n For more information, see the{' '}\n <Link href='https://dash.generaltranslation.com'>\n General Translation Dashboard\n </Link>\n .\n </Text>\n <Flex align='center' gap={2}>\n <Text size={1} muted>\n gt-sanity v{PACKAGE_VERSION}\n </Text>\n <Button\n fontSize={1}\n padding={2}\n mode='bleed'\n text='Debug info'\n onClick={() => setIsDebugInfoDialogOpen(true)}\n />\n </Flex>\n </Flex>\n </Card>\n </Stack>\n </Box>\n\n <TranslateAllDialog\n isOpen={isTranslateAllDialogOpen}\n onClose={() => setIsTranslateAllDialogOpen(false)}\n />\n <ImportAllDialog\n isOpen={isImportAllDialogOpen}\n onClose={() => setIsImportAllDialogOpen(false)}\n />\n <ImportMissingDialog\n isOpen={isImportMissingDialogOpen}\n onClose={() => setIsImportMissingDialogOpen(false)}\n />\n <SaveLocalTranslationsDialog\n isOpen={isSaveLocalDialogOpen}\n onClose={() => setIsSaveLocalDialogOpen(false)}\n onConfirm={() => {\n setPreserveExistingTranslations(true);\n setIsSaveLocalDialogOpen(false);\n }}\n />\n <UploadExistingDialog\n isOpen={isUploadExistingDialogOpen}\n onClose={() => setIsUploadExistingDialogOpen(false)}\n />\n <DebugInfoDialog\n isOpen={isDebugInfoDialogOpen}\n onClose={() => setIsDebugInfoDialogOpen(false)}\n />\n </Container>\n );\n};\n\nconst TranslationsTool: React.FC = () => {\n return (\n <BaseTranslationWrapper showContainer={false}>\n <TranslationsProvider>\n <TranslationsToolContent />\n </TranslationsProvider>\n </BaseTranslationWrapper>\n );\n};\n\nexport default TranslationsTool;\n","/**\n * `locales` is the list of translation *targets*, but configs often repeat the\n * source locale there β€” spreading `gt.config.json`, which pairs `defaultLocale`\n * with a `locales` array, is the common way to end up with it.\n *\n * A repeated locale is not cosmetic: it reaches\n * `@sanity/document-internationalization` as a duplicate `supportedLanguages`\n * entry, and `sanity-plugin-internationalized-array` then resolves every\n * language after the duplicate to the wrong array index. Its reorder effect\n * rewrites the array, re-renders, and re-flags the same mismatch forever, which\n * crashes the Studio with \"Maximum update depth exceeded\".\n */\nexport function resolveTargetLocales(\n sourceLocale: string,\n locales: string[] | undefined\n): string[] {\n return Array.from(new Set(locales)).filter(\n (locale) => locale !== sourceLocale\n );\n}\n","import { getLocaleProperties } from 'generaltranslation';\nimport { createDiagnosticMessage } from 'generaltranslation/internal';\nimport type {\n ListItemBuilder,\n StructureBuilder,\n StructureResolver,\n StructureResolverContext,\n} from 'sanity/structure';\nimport { pluginConfig } from '../adapter/core';\nimport { formatLocalePropertiesLabel } from '../utils/localeDisplay';\nimport { SANITY_API_VERSION } from '../utils/shared';\n\nexport type GTStructureOptions = {\n /**\n * Document types to group by locale. Defaults to the types in\n * `translateDocuments` that are translated into per-locale documents.\n */\n types?: string[];\n /** Title of the pane holding the source-locale documents. */\n sourceTitle?: string;\n /** Title of a locale's pane. Defaults to `<Type> in <Locale>`. */\n localeTitle?: (typeTitle: string, locale: string, label: string) => string;\n};\n\n/**\n * Document types translated into per-locale documents.\n *\n * Types localized through internationalized arrays are excluded: their\n * translations live inside the source document, so there is no per-locale\n * document to group.\n */\nfunction documentLevelTypes(): string[] {\n const level = pluginConfig.getTranslationLevel();\n const types = pluginConfig\n .getTranslateDocuments()\n .map((filter) => filter.type)\n .filter((type): type is string => Boolean(type));\n\n if (level === 'internationalizedArray') return [];\n if (level === 'mixed') {\n const fieldLevel = new Set(\n pluginConfig.getFieldLevelDocuments().map((filter) => filter.type)\n );\n return types.filter((type) => !fieldLevel.has(type));\n }\n return types;\n}\n\nfunction localeLabel(locale: string): string {\n const sourceLocale = pluginConfig.getSourceLocale();\n return formatLocalePropertiesLabel(\n locale,\n getLocaleProperties(locale, sourceLocale)\n );\n}\n\nfunction typeTitle(type: string, context?: StructureResolverContext): string {\n const schemaType = context?.schema?.get(type);\n return (schemaType?.title as string | undefined) ?? type;\n}\n\n/**\n * Builds one list item per translatable document type. Each expands into a\n * pane per locale, so translations are browsed by language instead of sitting\n * alongside their source in a single flat list.\n *\n * Returns an empty array when `translateDocuments` names no types, since the\n * grouping is per type.\n */\nexport function gtStructureItems(\n S: StructureBuilder,\n context?: StructureResolverContext,\n options: GTStructureOptions = {}\n): ListItemBuilder[] {\n const types = options.types ?? documentLevelTypes();\n\n if (types.length === 0) {\n console.warn(\n createDiagnosticMessage({\n source: 'gt-sanity',\n severity: 'Warning',\n whatHappened: 'No document types to group by locale',\n why: 'the structure helper groups per document type, and none were resolved from the plugin configuration',\n fix: 'List the types in `translateDocuments`, or pass them to the structure helper as `types`',\n })\n );\n return [];\n }\n\n const sourceLocale = pluginConfig.getSourceLocale();\n const languageField = pluginConfig.getLanguageField();\n const targetLocales = pluginConfig.getLocales();\n const titleFor =\n options.localeTitle ??\n ((title: string, _locale: string, label: string) => `${title} in ${label}`);\n\n return types.map((type) => {\n const title = typeTitle(type, context);\n\n // A document with no language field is the source: the plugin only\n // stamps the field on translations it creates, and existing content\n // predates the plugin.\n const sourceFilter = `_type == $type && (!defined(${languageField}) || ${languageField} == $locale)`;\n const localeFilter = `_type == $type && ${languageField} == $locale`;\n\n return S.listItem()\n .id(`gt-${type}`)\n .title(title)\n .child(\n S.list()\n .id(`gt-${type}-locales`)\n .title(title)\n .items([\n S.listItem()\n .id(`gt-${type}-${sourceLocale}`)\n .title(options.sourceTitle ?? localeLabel(sourceLocale))\n .child(\n S.documentList()\n .id(`gt-${type}-${sourceLocale}-list`)\n .title(options.sourceTitle ?? localeLabel(sourceLocale))\n .schemaType(type)\n .apiVersion(SANITY_API_VERSION)\n .filter(sourceFilter)\n .params({ type, locale: sourceLocale })\n ),\n S.divider(),\n ...targetLocales.map((locale) => {\n const paneTitle = titleFor(title, locale, localeLabel(locale));\n return S.listItem()\n .id(`gt-${type}-${locale}`)\n .title(paneTitle)\n .child(\n S.documentList()\n .id(`gt-${type}-${locale}-list`)\n .title(paneTitle)\n .schemaType(type)\n .apiVersion(SANITY_API_VERSION)\n .filter(localeFilter)\n .params({ type, locale })\n );\n }),\n ])\n );\n });\n}\n\n/**\n * A ready-made structure that lists every translatable type grouped by locale.\n *\n * Use `gtStructureItems` instead to place these alongside other list items.\n */\nexport function gtStructure(\n options: GTStructureOptions = {}\n): StructureResolver {\n return (S, context) =>\n S.list()\n .title('Content')\n .items(gtStructureItems(S, context, options));\n}\n","import React from 'react';\nimport { SanityDocument } from 'sanity';\nimport { BaseTranslationWrapper } from '../shared/BaseTranslationWrapper';\nimport { TranslationsProvider } from '../TranslationsProvider';\nimport { TranslationView } from './TranslationView';\n\ntype TranslationTabProps = {\n document: {\n displayed: SanityDocument;\n };\n};\n\nconst TranslationTab = (props: TranslationTabProps) => {\n const { displayed } = props.document;\n\n return (\n <BaseTranslationWrapper showContainer={false}>\n <TranslationsProvider singleDocument={displayed}>\n <TranslationView />\n </TranslationsProvider>\n </BaseTranslationWrapper>\n );\n};\n\nexport default TranslationTab;\n","import type { PortableTextHtmlComponents } from '@portabletext/to-html';\nimport { getLocaleProperties } from 'generaltranslation';\nimport {\n createDiagnosticMessage,\n libraryDefaultLocale,\n} from 'generaltranslation/internal';\nimport { formatLocalePropertiesLabel } from './utils/localeDisplay';\nimport { definePlugin } from 'sanity';\nimport { route } from 'sanity/router';\nimport { translateAction } from './actions/translateAction';\nimport {\n DEFAULT_TRANSLATION_PREFERENCES,\n gt,\n pluginConfig,\n} from './adapter/core';\nimport type {\n DedupeFields,\n IgnoreFields,\n SkipFields,\n TranslateDocumentFilter,\n FieldLevelTranslationMode,\n} from './adapter/types';\nimport {\n buildInternationalizedArrayPlugin,\n resolveFieldLevelConfig,\n} from './schema/fieldLevelConfig';\nimport type { GTFieldLevelLocalizationConfig } from './schema/fieldLevelConfig';\nimport './schema/schemaOptions';\nimport TranslationsTool from './components/page/TranslationsTool';\nimport { documentInternationalization } from './documentInternationalization';\nimport type { CustomDeserializers } from './serialization/types';\nimport { resolveTargetLocales } from './utils/locales';\nimport { SECRETS_NAMESPACE } from './utils/shared';\n\n// ===== Document Internationalization ===== //\nexport {\n useDocumentInternationalizationContext,\n DocumentInternationalizationMenu,\n useDeleteTranslationAction,\n useDuplicateWithTranslationsAction,\n} from './documentInternationalization';\nexport { documentInternationalization };\nexport type {\n DocumentInternationalizationConfig,\n Language,\n Metadata,\n TranslationReference,\n} from './documentInternationalization';\n\n// ===== Studio Structure ===== //\n// Grouping translations by locale is opt-in: the structure tool's layout is\n// owned by `structureTool({ structure })` in the Studio config, which a plugin\n// cannot set on the user's behalf.\nexport { gtStructure, gtStructureItems } from './structure/localizedStructure';\nexport type { GTStructureOptions } from './structure/localizedStructure';\n\n// ===== Serialization Helpers ===== //\nexport { default as TranslationsTab } from './components/tab/TranslationsTab';\nexport { findLatestDraft } from './configuration/utils/findLatestDraft';\nexport { BaseDocumentSerializer } from './serialization/serialize/index';\nexport { BaseDocumentDeserializer } from './serialization/deserialize/BaseDocumentDeserializer';\nexport { BaseDocumentMerger } from './serialization/BaseDocumentMerger';\nexport {\n defaultStopTypes,\n customSerializers,\n} from './serialization/BaseSerializationConfig';\nexport { attachGTData, detachGTData } from './serialization/data';\nexport { translateAction };\nexport type {\n Secrets,\n Adapter,\n ExportForTranslation,\n ImportTranslation,\n TranslationFunctionContext,\n TranslationsTabConfigOptions,\n} from './types';\nexport type { SerializedDocument } from './serialization/types';\n\n// ===== Field-Level (Internationalized Array) Localization ===== //\n// gt-sanity configures the reference plugin rather than shipping its own UI;\n// the plugin and its types are re-exported for direct/advanced use.\nexport {\n internationalizedArray,\n internationalizedArrayLanguageFilter,\n isInternationalizedArrayItemType,\n} from 'sanity-plugin-internationalized-array';\nexport type {\n PluginConfig as InternationalizedArrayPluginConfig,\n Language as InternationalizedArrayLanguage,\n} from 'sanity-plugin-internationalized-array';\nexport type {\n GTFieldLevelLocalizationConfig,\n FieldLevelFieldType,\n} from './schema/fieldLevelConfig';\nexport type { GTSchemaFieldOptions } from './schema/schemaOptions';\nexport type { FieldLevelTranslationMode };\n\nexport type GTPluginConfig = Omit<\n Parameters<typeof gt.setConfig>[0],\n 'locales'\n> & {\n locales: string[];\n // Alias for sourceLocale β€” accepted so users can spread gt.config.json directly.\n defaultLocale?: string;\n singletons?: string[];\n // Optional mapping function to map source document ids to translated singleton document ids\n // By default, the translated singleton document is is `${sourceDocumentId}-${locale}`\n singletonMapping?: (sourceDocumentId: string, locale: string) => string;\n ignoreFields?: IgnoreFields[];\n dedupeFields?: DedupeFields[];\n skipFields?: SkipFields[];\n languageField?: string;\n translateDocuments?: TranslateDocumentFilter[] | string[];\n secretsNamespace?: string;\n additionalStopTypes?: string[];\n additionalSerializers?: Partial<PortableTextHtmlComponents>;\n additionalDeserializers?: CustomDeserializers;\n additionalBlockDeserializers?: unknown[];\n // When true (default), automatically adds the @sanity/document-internationalization plugin\n // with language badges, translation menu, and per-language templates.\n // Requires translateDocuments to specify which document types to enable translations for.\n showDocumentInternationalization?: boolean;\n // Field-level (internationalized-array) localization. When enabled,\n // auto-configures sanity-plugin-internationalized-array (the reference\n // plugin, which owns the schema types and Studio UI) from this plugin's\n // locales. Leave disabled if you register that plugin yourself.\n // `fieldLevelLocalization` is a descriptive alias for the same config.\n internationalizedArray?: GTFieldLevelLocalizationConfig;\n fieldLevelLocalization?: GTFieldLevelLocalizationConfig;\n // How matched documents are translated. Independent from schema setup:\n // enabling `internationalizedArray` only adds editable fields; routing\n // translation through the array path requires opting in here. Default 'document'.\n translationLevel?: FieldLevelTranslationMode;\n // In 'mixed' mode, the document types that use the internationalized-array\n // strategy; everything else stays document-level.\n fieldLevelDocuments?: TranslateDocumentFilter[] | string[];\n // Sets the initial state of the \"Local translations win\" toggle. When on,\n // the translations currently in Sanity are uploaded to General Translation\n // before a translation run, so they become the baseline the next translation\n // reuses. Local content overwrites whatever General Translation holds for\n // that source version, including a completed translation that has not been\n // imported yet. Off by default; the toggle can be flipped per session.\n preserveExistingTranslations?: boolean;\n // Starting state of the automatic actions in the translations UI. These are\n // defaults, not locks: a change the user makes in the Studio is remembered in\n // localStorage (per project and dataset) and preferred on their next visit.\n // Defaults to true.\n autoRefresh?: boolean;\n // Import a translation as soon as it completes. Defaults to true.\n autoImport?: boolean;\n // Repoint references to their translated counterparts after import. Defaults\n // to FALSE β€” when a translated document has already been published and has no\n // draft, the rewrite is applied to a draft seeded from it, so this edits\n // documents you may consider finished.\n autoPatchReferences?: boolean;\n // Publish translated documents after import. Defaults to FALSE β€” publishing\n // is the one automatic action that puts content in front of readers and\n // cannot be undone by turning the switch back off.\n autoPublish?: boolean;\n};\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import {defineConfig} from 'sanity'\n * import {gtPlugin} from 'gt-sanity'\n *\n * export default defineConfig({\n * // ...\n * plugins: [gtPlugin()],\n * })\n * ```\n */\nexport const gtPlugin = definePlugin<GTPluginConfig>(\n ({\n languageField = 'language',\n sourceLocale,\n defaultLocale,\n locales,\n customMapping,\n apiKey,\n projectId,\n singletons,\n singletonMapping,\n ignoreFields,\n dedupeFields,\n skipFields,\n translateDocuments,\n secretsNamespace = SECRETS_NAMESPACE,\n additionalStopTypes = [],\n additionalSerializers = {},\n additionalDeserializers = {},\n additionalBlockDeserializers = [],\n showDocumentInternationalization = true,\n internationalizedArray,\n fieldLevelLocalization,\n translationLevel = 'document',\n fieldLevelDocuments,\n preserveExistingTranslations = DEFAULT_TRANSLATION_PREFERENCES.preserveExistingTranslations,\n autoRefresh = DEFAULT_TRANSLATION_PREFERENCES.autoRefresh,\n autoImport = DEFAULT_TRANSLATION_PREFERENCES.autoImport,\n autoPatchReferences = DEFAULT_TRANSLATION_PREFERENCES.autoPatchReferences,\n autoPublish = DEFAULT_TRANSLATION_PREFERENCES.autoPublish,\n }) => {\n // Resolve sourceLocale: explicit sourceLocale > defaultLocale (from gt.config.json) > library default\n const resolvedSourceLocale =\n sourceLocale ?? defaultLocale ?? libraryDefaultLocale;\n\n // `locales` holds translation targets only. Drop duplicates and the source\n // locale before anything downstream sees them β€” a repeated locale reaches\n // the Studio as a duplicate language and breaks the translations UI.\n const targetLocales = resolveTargetLocales(resolvedSourceLocale, locales);\n\n // Normalize translateDocuments: string[] β†’ TranslateDocumentFilter[]\n const normalizeFilters = (\n entries: (TranslateDocumentFilter | string)[] | undefined\n ): TranslateDocumentFilter[] | undefined =>\n entries\n ?.map((entry) => (typeof entry === 'string' ? { type: entry } : entry))\n .filter((filter) => filter.documentId || filter.type);\n\n const normalizedTranslateDocuments = normalizeFilters(translateDocuments);\n const normalizedFieldLevelDocuments =\n normalizeFilters(fieldLevelDocuments) ?? [];\n\n // `internationalizedArray` and `fieldLevelLocalization` are aliases.\n const rawFieldLevelConfig =\n internationalizedArray ?? fieldLevelLocalization;\n warnOnRemovedFieldLevelOptions(rawFieldLevelConfig);\n const fieldLevelConfig = resolveFieldLevelConfig(rawFieldLevelConfig);\n\n pluginConfig.init(\n secretsNamespace,\n languageField,\n resolvedSourceLocale,\n targetLocales,\n singletons || [],\n // singletons is a string array of singleton document ids\n singletonMapping ||\n ((sourceDocumentId, locale) => `${sourceDocumentId}-${locale}`),\n ignoreFields || [],\n dedupeFields || [],\n skipFields || [],\n normalizedTranslateDocuments || [],\n additionalStopTypes,\n additionalSerializers,\n additionalDeserializers,\n additionalBlockDeserializers,\n translationLevel,\n normalizedFieldLevelDocuments,\n {\n autoRefresh,\n autoImport,\n autoPatchReferences,\n autoPublish,\n preserveExistingTranslations,\n }\n );\n gt.setConfig({\n sourceLocale: resolvedSourceLocale,\n customMapping: customMapping,\n apiKey: apiKey,\n projectId: projectId,\n });\n\n // Document types localized in place via internationalized arrays must NOT\n // get @sanity/document-internationalization (language badges + per-locale\n // documents). Build the set of array-localized types from translationLevel.\n const arrayLocalizedTypes = new Set<string>();\n if (translationLevel === 'internationalizedArray') {\n normalizedTranslateDocuments\n ?.map((filter) => filter.type)\n .filter((type): type is string => !!type)\n .forEach((type) => arrayLocalizedTypes.add(type));\n } else if (translationLevel === 'mixed') {\n normalizedFieldLevelDocuments\n .map((filter) => filter.type)\n .filter((type): type is string => !!type)\n .forEach((type) => arrayLocalizedTypes.add(type));\n }\n\n // Auto-add document internationalization plugin\n const plugins = [];\n if (showDocumentInternationalization) {\n const schemaTypes =\n normalizedTranslateDocuments\n ?.map((filter) => filter.type)\n .filter((type): type is string => !!type)\n .filter((type) => !arrayLocalizedTypes.has(type)) ?? [];\n if (schemaTypes.length > 0) {\n const allLocales = [resolvedSourceLocale, ...targetLocales];\n const supportedLanguages = allLocales.map((locale) => {\n const props = getLocaleProperties(\n locale,\n resolvedSourceLocale,\n customMapping\n );\n return {\n id: locale,\n title: formatLocalePropertiesLabel(\n locale,\n props,\n customMapping?.[locale]\n ),\n };\n });\n plugins.push(\n documentInternationalization({\n supportedLanguages,\n schemaTypes,\n languageField,\n })\n );\n }\n }\n\n // Field-level localization is provided by the reference plugin,\n // configured from gtPlugin's locales. Users who already register\n // sanity-plugin-internationalized-array themselves should leave this\n // disabled β€” translation only reads the stored data shape.\n if (fieldLevelConfig.enabled) {\n plugins.push(\n buildInternationalizedArrayPlugin(\n fieldLevelConfig,\n resolvedSourceLocale,\n targetLocales,\n customMapping\n )\n );\n }\n\n return {\n name: 'gt-sanity',\n plugins,\n tools: [\n {\n name: 'translations',\n title: 'Translations',\n component: TranslationsTool,\n router: route.create('/*'),\n },\n ],\n document: {\n actions: (prev) => {\n return [...prev, translateAction];\n },\n },\n };\n }\n);\n\n// Options that existed while gt-sanity shipped its own field-level UI (v2.1.x)\n// and have no equivalent in sanity-plugin-internationalized-array.\nconst REMOVED_FIELD_LEVEL_OPTIONS = [\n 'typePrefix',\n 'includeCompatibilityTypes',\n 'components',\n] as const;\n\nfunction warnOnRemovedFieldLevelOptions(\n config: GTFieldLevelLocalizationConfig | undefined\n): void {\n if (!config) return;\n const removed = REMOVED_FIELD_LEVEL_OPTIONS.filter(\n (key) => (config as Record<string, unknown>)[key] !== undefined\n );\n if (removed.length === 0) return;\n console.warn(\n createDiagnosticMessage({\n source: 'gt-sanity',\n severity: 'Warning',\n whatHappened: `Ignored unsupported field-level localization ${removed.length === 1 ? 'option' : 'options'}`,\n why: 'field-level localization is now provided by sanity-plugin-internationalized-array, which has no equivalent for these options',\n fix: 'Remove them from the gtPlugin configuration',\n details: removed,\n })\n );\n}\n"],"names":["useSanityClient","isRecord","document","deserializeDocument","META_FIELDS","isPlainRecord","branchId","existingTranslations","secrets","PACKAGE_VERSION","internationalizedArray"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/adapter/api.ts","../src/utils/shared.ts","../src/adapter/core.ts","../src/utils/localeDisplay.ts","../src/hooks/useClient.ts","../src/hooks/useSecrets.ts","../src/components/shared/BaseTranslationWrapper.tsx","../src/serialization/BaseDocumentMerger.ts","../src/utils/documentIds.ts","../src/configuration/utils/findLatestDraft.ts","../src/configuration/utils/findDocumentAtRevision.ts","../src/configuration/utils/requireSourceDocument.ts","../src/utils/applyDocuments.ts","../src/utils/randomKey.ts","../src/utils/translationMetadata.ts","../src/configuration/baseDocumentLevelConfig/helpers/createI18nDocAndPatchMetadata.ts","../src/configuration/baseDocumentLevelConfig/helpers/getOrCreateTranslationMetadata.ts","../src/configuration/baseDocumentLevelConfig/helpers/patchI18nDoc.ts","../src/configuration/baseDocumentLevelConfig/documentLevelPatch.ts","../src/serialization/internationalizedArray/detect.ts","../src/serialization/internationalizedArray/merge.ts","../src/configuration/internationalizedArrayConfig/internationalizedArrayPatch.ts","../src/serialization/deserialize/helpers.ts","../src/serialization/data.ts","../src/serialization/BaseSerializationConfig.ts","../src/serialization/helpers.ts","../src/serialization/deserialize/BaseDocumentDeserializer.ts","../src/serialization/serialize/fieldFilters.ts","../src/serialization/serialize/index.ts","../src/serialization/internationalizedArray/collapse.ts","../src/utils/serialize.ts","../src/translation/strategy.ts","../src/translation/uploadFiles.ts","../src/translation/initProject.ts","../src/translation/createJobs.ts","../src/translation/collectExistingTranslations.ts","../src/translation/captureExistingTranslations.ts","../src/translation/uploadTranslations.ts","../src/translation/downloadTranslations.ts","../src/translation/checkTranslationStatus.ts","../src/translation/importDocument.ts","../src/sanity-api/resolveRefs.ts","../src/sanity-api/findDocuments.ts","../src/utils/batchProcessor.ts","../src/utils/importUtils.ts","../src/sanity-api/publishDocuments.ts","../src/adapter/getLocales.ts","../src/utils/translationPreferences.ts","../src/components/TranslationsProvider.tsx","../src/components/page/SaveLocalTranslationsDialog.tsx","../src/utils/debugInfo.ts","../src/utils/translationSummary.ts","../src/components/page/DebugInfoDialog.tsx","../src/components/shared/LocaleLabel.tsx","../src/components/shared/LanguageStatus.tsx","../src/utils/languageStatusState.ts","../src/components/shared/LocaleCheckbox.tsx","../src/components/tab/TranslationView.tsx","../src/actions/translateAction.tsx","../src/schema/fieldLevelConfig.ts","../src/components/page/TranslationsTable.tsx","../src/components/page/TranslateAllDialog.tsx","../src/components/page/ImportAllDialog.tsx","../src/components/page/ImportMissingDialog.tsx","../src/components/page/UploadExistingDialog.tsx","../src/components/page/BatchProgress.tsx","../src/components/page/TranslationsTool.tsx","../src/utils/locales.ts","../src/structure/localizedStructure.ts","../src/components/tab/TranslationsTab.tsx","../src/index.ts"],"sourcesContent":["import {\n awaitJobs as awaitApiJobs,\n createApiClient,\n createBranch,\n decodeFileContent,\n downloadFile,\n downloadFiles,\n encodeFileContent,\n enqueueFileTranslations,\n generateProjectContext,\n getFileInfo,\n getTranslationStatus,\n processBatches,\n uploadSourceFiles,\n uploadTranslations,\n type ApiClientConfig,\n type CreateBranchData,\n type DownloadFilesData,\n type EnqueueFileTranslationsData,\n type GenerateProjectContextData,\n type GetFileInfoData,\n type UploadSourceFilesData,\n type UploadTranslationsData,\n} from 'generaltranslation/api';\nimport { resolveAliasLocale, resolveCanonicalLocale } from 'generaltranslation';\nimport {\n decode as decodeBase64,\n defaultBaseUrl,\n unwrapApiResult,\n} from 'generaltranslation/internal';\nimport type { CustomMapping, DownloadedFile } from 'generaltranslation/types';\n\nlet client = createApiClient({ baseUrl: defaultBaseUrl });\nlet customMapping: CustomMapping | undefined;\n\nexport function configureApiClient(\n config: Omit<ApiClientConfig, 'baseUrl'> & {\n baseUrl?: string;\n customMapping?: CustomMapping;\n }\n): void {\n const { customMapping: mapping, ...clientConfig } = config;\n client = createApiClient({\n baseUrl: defaultBaseUrl,\n ...clientConfig,\n });\n customMapping = mapping;\n}\n\nexport const api = {\n async uploadSourceFiles(\n files: Array<{\n source: UploadSourceFilesData['body']['data'][number]['source'];\n }>,\n options: { sourceLocale: string }\n ) {\n const sourceLocale = resolveCanonicalLocale(\n options.sourceLocale,\n customMapping\n );\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadSourceFiles({\n body: {\n data: batch.map(({ source }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n locale: resolveCanonicalLocale(source.locale, customMapping),\n },\n })),\n sourceLocale,\n },\n client,\n })\n );\n return response.uploadedFiles;\n });\n return { uploadedFiles: result };\n },\n\n async uploadTranslations(\n files: UploadTranslationsData['body']['data'],\n options: { sourceLocale: string }\n ) {\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadTranslations({\n body: {\n data: batch.map(({ source, translations }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n },\n translations: translations.map((translation) => ({\n ...translation,\n content: encodeFileContent(\n translation.content,\n translation.fileFormat\n ),\n locale: resolveCanonicalLocale(\n translation.locale,\n customMapping\n ),\n })),\n })),\n sourceLocale: resolveCanonicalLocale(\n options.sourceLocale,\n customMapping\n ),\n },\n client,\n })\n );\n return response.uploadedFiles;\n });\n return { uploadedFiles: result };\n },\n\n async enqueueFiles(\n files: EnqueueFileTranslationsData['body']['files'],\n options: {\n sourceLocale?: string;\n targetLocales: string[];\n force?: boolean;\n }\n ) {\n const sourceLocale = options.sourceLocale\n ? resolveCanonicalLocale(options.sourceLocale, customMapping)\n : undefined;\n const targetLocales = options.targetLocales.map((locale) =>\n resolveCanonicalLocale(locale, customMapping)\n );\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await enqueueFileTranslations({\n body: {\n files: batch,\n sourceLocale,\n targetLocales,\n force: options.force,\n },\n client,\n })\n );\n return Object.entries(\n 'jobData' in response ? response.jobData : response.data\n );\n });\n return { jobData: Object.fromEntries(result), locales: targetLocales };\n },\n\n async querySourceFile(query: {\n fileId: string;\n versionId?: string;\n branchId?: string;\n }) {\n const { fileId, ...queryParams } = query;\n const result = unwrapApiResult(\n await getTranslationStatus({\n path: { fileId },\n query: queryParams,\n client,\n })\n );\n return {\n ...result,\n translations: result.translations.map((translation) => ({\n ...translation,\n locale: resolveAliasLocale(translation.locale, customMapping),\n })),\n sourceFile: {\n ...result.sourceFile,\n sourceLocale: resolveAliasLocale(\n result.sourceFile.sourceLocale,\n customMapping\n ),\n locales: result.sourceFile.locales.map((locale) =>\n resolveAliasLocale(locale, customMapping)\n ),\n },\n };\n },\n\n async downloadFile(query: {\n fileId: string;\n versionId?: string;\n branchId?: string;\n locale?: string;\n }) {\n const { fileId, locale, ...queryParams } = query;\n const response = unwrapApiResult(\n await downloadFile({\n path: { fileId },\n query: {\n ...queryParams,\n locale: locale\n ? resolveCanonicalLocale(locale, customMapping)\n : undefined,\n },\n client,\n })\n );\n // The single-file response omits fileFormat; Sanity downloads serialized\n // document translations here, which are always base64 text (never LOTTIE).\n return decodeBase64(response.data);\n },\n\n async downloadFileBatch(files: DownloadFilesData['body']) {\n if (files.length === 0) return { files: [], count: 0 };\n\n const request = async (batch: DownloadFilesData['body']) =>\n unwrapApiResult(\n await downloadFiles({\n body: batch.map((file) => ({\n ...file,\n locale: file.locale\n ? resolveCanonicalLocale(file.locale, customMapping)\n : undefined,\n })),\n client,\n })\n );\n const responses = await processBatches(files, async (batch) => [\n await request(batch),\n ]);\n return {\n files: responses.flatMap((response) =>\n response.files.map((file) => ({\n ...file,\n ...(file.locale && {\n locale: resolveAliasLocale(file.locale, customMapping),\n }),\n data: decodeFileContent(file.data, file.fileFormat),\n // OpenAPI currently types metadata as an open object; the API emits\n // JSON values here, matching DownloadedFile's public contract.\n metadata: file.metadata as DownloadedFile['metadata'],\n }))\n ),\n count: responses.reduce((count, response) => count + response.count, 0),\n };\n },\n\n async setupProject(\n files: GenerateProjectContextData['body']['files'],\n options: Omit<GenerateProjectContextData['body'], 'files'> = {}\n ) {\n return unwrapApiResult(\n await generateProjectContext({ body: { files, ...options }, client })\n );\n },\n\n async awaitJobs(\n jobIds: readonly string[],\n options?: Parameters<typeof awaitApiJobs>[2]\n ) {\n return awaitApiJobs(client, jobIds, options);\n },\n\n async queryFileData(body: GetFileInfoData['body']) {\n const result = unwrapApiResult(\n await getFileInfo({\n body: {\n ...body,\n translatedFiles: body.translatedFiles?.map((file) => ({\n ...file,\n locale: resolveCanonicalLocale(file.locale, customMapping),\n })),\n },\n client,\n })\n );\n return {\n ...result,\n translatedFiles: result.translatedFiles.map((file) => ({\n ...file,\n locale: resolveAliasLocale(file.locale, customMapping),\n })),\n sourceFiles: result.sourceFiles.map((file) => ({\n ...file,\n sourceLocale: resolveAliasLocale(file.sourceLocale, customMapping),\n locales: file.locales.map((locale) =>\n resolveAliasLocale(locale, customMapping)\n ),\n })),\n };\n },\n\n async createBranch(body: CreateBranchData['body']) {\n return unwrapApiResult(await createBranch({ body, client }));\n },\n};\n","export const SECRETS_NAMESPACE = 'generaltranslation.secrets';\n\n/**\n * Sanity API version used by every client and structure builder this plugin\n * creates. Sanity requires a pinned version on document lists that supply a\n * custom filter, and warns when one is omitted.\n */\nexport const SANITY_API_VERSION = '2025-09-15';\n","import { GT } from 'generaltranslation';\nimport { configureApiClient } from './api';\n\nexport { api } from './api';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport type { Secrets } from '../types';\nimport type {\n TranslateDocumentFilter,\n DedupeFields,\n IgnoreFields,\n SkipFields,\n FieldLevelTranslationMode,\n TranslationPreferences,\n} from './types';\nimport { SECRETS_NAMESPACE } from '../utils/shared';\nimport type { PortableTextHtmlComponents } from '@portabletext/to-html';\nimport type { CustomDeserializers } from '../serialization/types';\nexport const gt = new GT();\n\n/**\n * Built-in defaults for the automatic actions.\n *\n * The line is whether an action can put content in front of readers, or write\n * to something already in front of them:\n * - `autoRefresh` only polls for status, and auto-import depends on it.\n * - `autoImport` writes drafts, which are cheap to discard.\n * - `autoPatchReferences` normally writes a draft too, but rewrites references\n * on an already-published translation when that document has no draft, so it\n * is opt-in.\n * - `autoPublish` publishes, which no switch can undo.\n */\nexport const DEFAULT_TRANSLATION_PREFERENCES: TranslationPreferences = {\n autoRefresh: true,\n autoImport: true,\n autoPatchReferences: false,\n autoPublish: false,\n // Opt-in: turning this on means Sanity overwrites whatever General\n // Translation holds for that source version, including a completed\n // translation that has not been imported yet.\n preserveExistingTranslations: false,\n};\n\nexport function overrideConfig(secrets: Secrets | null) {\n const config = {\n ...(secrets?.project && { projectId: secrets.project }),\n ...(secrets?.secret && { apiKey: secrets.secret }),\n };\n gt.setConfig(config);\n configureApiClient({ ...config, customMapping: gt.customMapping });\n}\n\nexport class GTConfig {\n secretsNamespace: string;\n languageField: string;\n sourceLocale: string;\n locales: string[];\n singletons: string[];\n singletonMapping: (sourceDocumentId: string, locale: string) => string;\n ignoreFields: IgnoreFields[];\n dedupeFields: DedupeFields[];\n skipFields: SkipFields[];\n translateDocuments: TranslateDocumentFilter[];\n additionalStopTypes: string[];\n additionalSerializers: Partial<PortableTextHtmlComponents>;\n additionalDeserializers: CustomDeserializers;\n additionalBlockDeserializers: unknown[];\n translationLevel: FieldLevelTranslationMode;\n fieldLevelDocuments: TranslateDocumentFilter[];\n preferences: TranslationPreferences;\n\n private static instance: GTConfig;\n constructor(\n secretsNamespace: string,\n languageField: string,\n sourceLocale: string,\n locales: string[],\n singletons: string[],\n singletonMapping: (sourceDocumentId: string, locale: string) => string,\n ignoreFields: IgnoreFields[],\n dedupeFields: DedupeFields[],\n skipFields: SkipFields[],\n translateDocuments: TranslateDocumentFilter[],\n additionalStopTypes: string[] = [],\n additionalSerializers: Partial<PortableTextHtmlComponents> = {},\n additionalDeserializers: CustomDeserializers = { types: {} },\n additionalBlockDeserializers: unknown[] = [],\n translationLevel: FieldLevelTranslationMode = 'document',\n fieldLevelDocuments: TranslateDocumentFilter[] = [],\n preferences: TranslationPreferences = DEFAULT_TRANSLATION_PREFERENCES\n ) {\n this.secretsNamespace = secretsNamespace;\n this.languageField = languageField;\n this.sourceLocale = sourceLocale;\n this.locales = locales;\n this.singletons = singletons;\n this.singletonMapping = singletonMapping;\n this.ignoreFields = ignoreFields;\n this.dedupeFields = dedupeFields;\n this.skipFields = skipFields;\n this.translateDocuments = translateDocuments;\n this.additionalStopTypes = additionalStopTypes;\n this.additionalSerializers = additionalSerializers;\n this.additionalDeserializers = additionalDeserializers;\n this.additionalBlockDeserializers = additionalBlockDeserializers;\n this.translationLevel = translationLevel;\n this.fieldLevelDocuments = fieldLevelDocuments;\n this.preferences = preferences;\n }\n\n static getInstance() {\n if (!this.instance) {\n this.instance = new GTConfig(\n SECRETS_NAMESPACE,\n 'language',\n gt.sourceLocale || libraryDefaultLocale,\n [],\n [],\n () => '',\n [],\n [],\n [],\n [],\n [],\n { types: {} },\n {},\n []\n );\n }\n return this.instance;\n }\n\n init(\n secretsNamespace: string,\n languageField: string,\n sourceLocale: string,\n locales: string[],\n singletons: string[],\n singletonMapping: (sourceDocumentId: string, locale: string) => string,\n ignoreFields: IgnoreFields[],\n dedupeFields: DedupeFields[],\n skipFields: SkipFields[],\n translateDocuments: TranslateDocumentFilter[],\n additionalStopTypes: string[] = [],\n additionalSerializers: Partial<PortableTextHtmlComponents> = {},\n additionalDeserializers: CustomDeserializers = { types: {} },\n additionalBlockDeserializers: unknown[] = [],\n translationLevel: FieldLevelTranslationMode = 'document',\n fieldLevelDocuments: TranslateDocumentFilter[] = [],\n preferences: TranslationPreferences = DEFAULT_TRANSLATION_PREFERENCES\n ) {\n this.secretsNamespace = secretsNamespace;\n this.languageField = languageField;\n this.sourceLocale = sourceLocale;\n this.locales = locales;\n this.singletons = singletons;\n this.singletonMapping = singletonMapping;\n this.ignoreFields = ignoreFields;\n this.dedupeFields = dedupeFields;\n this.skipFields = skipFields;\n this.translateDocuments = translateDocuments;\n this.additionalStopTypes = additionalStopTypes;\n this.additionalSerializers = additionalSerializers;\n this.additionalDeserializers = additionalDeserializers;\n this.additionalBlockDeserializers = additionalBlockDeserializers;\n this.translationLevel = translationLevel;\n this.fieldLevelDocuments = fieldLevelDocuments;\n this.preferences = preferences;\n }\n\n getSecretsNamespace() {\n return this.secretsNamespace;\n }\n\n getLanguageField() {\n return this.languageField;\n }\n\n getSourceLocale() {\n return this.sourceLocale;\n }\n getLocales() {\n return this.locales;\n }\n getSingletons() {\n return this.singletons;\n }\n getSingletonMapping() {\n return this.singletonMapping;\n }\n getIgnoreFields() {\n return this.ignoreFields;\n }\n getDedupeFields() {\n return this.dedupeFields;\n }\n getSkipFields() {\n return this.skipFields;\n }\n getTranslateDocuments() {\n return this.translateDocuments;\n }\n getAdditionalStopTypes() {\n return this.additionalStopTypes;\n }\n getAdditionalSerializers() {\n return this.additionalSerializers;\n }\n getAdditionalDeserializers() {\n return this.additionalDeserializers;\n }\n getAdditionalBlockDeserializers() {\n return this.additionalBlockDeserializers;\n }\n getTranslationLevel() {\n return this.translationLevel;\n }\n getFieldLevelDocuments() {\n return this.fieldLevelDocuments;\n }\n getPreferences() {\n return this.preferences;\n }\n}\nexport const pluginConfig = GTConfig.getInstance();\n","import type { CustomMapping, LocaleProperties } from 'generaltranslation/types';\nimport { gt } from '../adapter/core';\n\ntype CustomMappingEntry = CustomMapping[string];\n\nexport type LocaleDisplay = {\n /** The locale code as configured, e.g. `en-US`. */\n code: string;\n /** Plain language name, e.g. `English` (never `American English`). */\n name: string;\n /** Flag emoji for the locale's region, e.g. πŸ‡ΊπŸ‡Έ. */\n emoji: string;\n /**\n * True when a string custom mapping fully defines the label: `name` is the\n * user's exact text and nothing (flag, code) should be added around it.\n */\n verbatim: boolean;\n};\n\nfunction capitalize(value: string): string {\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nexport function localeDisplayFromProperties(\n code: string,\n properties: LocaleProperties,\n mapping?: CustomMappingEntry\n): LocaleDisplay {\n // A string custom mapping replaces the entire label, flag included.\n // (The object form overrides individual properties instead, so it still\n // composes with the flag/code formatting.)\n if (typeof mapping === 'string') {\n return { code, name: mapping, emoji: '', verbatim: true };\n }\n return {\n code,\n name: capitalize(properties.languageName || properties.name || code),\n emoji: properties.emoji || '',\n verbatim: false,\n };\n}\n\n/**\n * Display parts for a locale, respecting the plugin's custom locale mapping.\n * Uses the bare language name plus the locale code so regional variants read\n * as e.g. `πŸ‡ΊπŸ‡Έ English (en-US)` instead of `American English`.\n */\nexport function getLocaleDisplay(localeId: string): LocaleDisplay {\n return localeDisplayFromProperties(\n localeId,\n gt.getLocaleProperties(localeId),\n gt.customMapping?.[localeId]\n );\n}\n\n/** Single-string form built from precomputed properties. */\nexport function formatLocalePropertiesLabel(\n code: string,\n properties: LocaleProperties,\n mapping?: CustomMappingEntry\n): string {\n const { emoji, name, verbatim } = localeDisplayFromProperties(\n code,\n properties,\n mapping\n );\n if (verbatim) return name;\n return [emoji, `${name} (${code})`].filter(Boolean).join(' ');\n}\n\n/** Single-string form, e.g. `πŸ‡ΊπŸ‡Έ English (en-US)`. */\nexport function formatLocaleLabel(localeId: string): string {\n return formatLocalePropertiesLabel(\n localeId,\n gt.getLocaleProperties(localeId),\n gt.customMapping?.[localeId]\n );\n}\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { SanityClient, useClient as useSanityClient } from 'sanity';\nimport { SANITY_API_VERSION } from '../utils/shared';\n\nexport const useClient = (): SanityClient => {\n return useSanityClient({ apiVersion: SANITY_API_VERSION });\n};\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { useState, useEffect } from 'react';\nimport { SanityDocumentLike } from 'sanity';\nimport { useClient } from './useClient';\n\ninterface ReturnProps<T> {\n loading: boolean;\n secrets: T | null;\n}\nexport function useSecrets<T>(id: string): ReturnProps<T> {\n const [loading, setLoading] = useState<boolean>(true);\n const [secrets, setSecrets] = useState<T | null>(null);\n const client = useClient();\n\n useEffect(() => {\n function fetchData() {\n client\n .fetch('* [_id == $id][0]', { id })\n .then((doc: SanityDocumentLike) => {\n const result: Record<string, unknown> = {};\n for (const key in doc) {\n if (key[0] !== '_') {\n result[key] = doc[key];\n }\n }\n setSecrets(result as T);\n setLoading(false);\n });\n }\n fetchData();\n }, [id, client]);\n\n return { loading, secrets };\n}\n","import React from 'react';\nimport { ThemeProvider, Box, Card, Flex, Spinner, Text } from '@sanity/ui';\nimport { ToastProvider } from '@sanity/ui/toast';\nimport { buildTheme } from '@sanity/ui/theme';\nimport { useSecrets } from '../../hooks/useSecrets';\nimport { Secrets } from '../../types';\nimport { pluginConfig } from '../../adapter/core';\n\n// GT's design system rounds nearly every surface to 6px (rounded-md). Bump\n// the default radius steps so plugin buttons/cards/inputs match without\n// having to set `radius` on every component.\nconst gtRadius = [0, 4, 6, 8, 12, 16, 24];\nconst baseTheme = buildTheme();\nconst theme = {\n ...baseTheme,\n radius: gtRadius,\n v2: baseTheme.v2 && { ...baseTheme.v2, radius: gtRadius },\n};\n\ninterface BaseTranslationWrapperProps {\n children: React.ReactNode;\n secretsNamespace?: string;\n padding?: number;\n showContainer?: boolean;\n}\n\nexport const BaseTranslationWrapper: React.FC<BaseTranslationWrapperProps> = ({\n children,\n secretsNamespace = pluginConfig.getSecretsNamespace(),\n padding = 4,\n showContainer = true,\n}) => {\n const { loading: loadingSecrets, secrets } =\n useSecrets<Secrets>(secretsNamespace);\n\n const content = (\n <>\n {loadingSecrets && (\n <Flex padding={5} align='center' justify='center'>\n <Spinner />\n </Flex>\n )}\n\n {!loadingSecrets && !secrets && (\n <Box padding={padding}>\n <Card tone='caution' padding={[2, 3, 4, 4]} shadow={1} radius={2}>\n <Text>\n Can't find secrets for your translation service. Did you load them\n into this dataset?\n </Text>\n </Card>\n </Box>\n )}\n\n {!loadingSecrets && secrets && children}\n </>\n );\n\n return (\n <ThemeProvider theme={theme}>\n <ToastProvider paddingY={7}>\n {showContainer ? <Box padding={padding}>{content}</Box> : content}\n </ToastProvider>\n </ThemeProvider>\n );\n};\n\nexport interface UseTranslationSecretsResult {\n loadingSecrets: boolean;\n secrets: Secrets | null;\n}\n\nexport const useTranslationSecrets = (\n secretsNamespace?: string\n): UseTranslationSecretsResult => {\n const { loading: loadingSecrets, secrets } = useSecrets<Secrets>(\n secretsNamespace || 'translationService.secrets'\n );\n\n return {\n loadingSecrets,\n secrets,\n };\n};\n","// Adapted from https://github.com/sanity-io/sanity-naive-html-serializer\n\nimport { Merger } from './types';\nimport { SanityDocument } from 'sanity';\nimport { extractWithPath, arrayToJSONMatchPath } from '@sanity/mutator';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst reconcileArray = (\n origArray: unknown[],\n translatedArray: unknown[]\n): unknown[] => {\n //arrays of strings don't have keys, so just replace the array and return\n if (translatedArray && translatedArray.some((el) => typeof el === 'string')) {\n return translatedArray;\n }\n\n //deep copy needed for field level patching\n const combined = JSON.parse(JSON.stringify(origArray)) as unknown[];\n\n translatedArray.forEach((translatedItem) => {\n if (!isRecord(translatedItem) || !translatedItem._key) {\n return;\n }\n const foundBlockIdx = origArray.findIndex(\n (origBlock) =>\n isRecord(origBlock) && origBlock._key === translatedItem._key\n );\n if (foundBlockIdx < 0) {\n //eslint-disable-next-line no-console\n console.warn(\n `This block no longer exists on the original document. Was it removed? ${JSON.stringify(\n translatedItem\n )}`\n );\n } else if (\n isRecord(origArray[foundBlockIdx]) &&\n (origArray[foundBlockIdx]._type === 'block' ||\n origArray[foundBlockIdx]._type === 'span')\n ) {\n combined[foundBlockIdx] = translatedItem;\n } else if (isRecord(origArray[foundBlockIdx])) {\n combined[foundBlockIdx] = reconcileObject(\n origArray[foundBlockIdx],\n translatedItem\n );\n }\n });\n return combined;\n};\n\nconst reconcileObject = (\n origObject: Record<string, unknown>,\n translatedObject: Record<string, unknown>\n): Record<string, unknown> => {\n if (\n typeof translatedObject !== 'object' ||\n !Object.keys(translatedObject).length\n ) {\n return origObject;\n }\n\n const updatedObj = JSON.parse(JSON.stringify(origObject)) as Record<\n string,\n unknown\n >;\n Object.entries(translatedObject).forEach(([key, value]) => {\n if (!value || key[0] === '_') {\n return;\n }\n if (typeof value === 'string') {\n updatedObj[key] = value;\n } else if (Array.isArray(value)) {\n updatedObj[key] = reconcileArray(\n Array.isArray(origObject[key]) ? origObject[key] : [],\n value\n );\n } else if (isRecord(value)) {\n updatedObj[key] = reconcileObject(\n isRecord(origObject[key]) ? origObject[key] : {},\n value\n );\n }\n });\n return updatedObj;\n};\n\nconst fieldLevelMerge = (\n translatedFields: Record<string, unknown>,\n //should be fetched according to the revision and id of the translated obj above\n baseDoc: SanityDocument,\n localeId: string,\n baseLang: string = libraryDefaultLocale\n): Record<string, unknown> => {\n const merged: Record<string, unknown> = {};\n const metaKeys = ['_rev', '_id', '_type'];\n metaKeys.forEach((metaKey) => {\n if (translatedFields[metaKey]) {\n merged[metaKey] = translatedFields[metaKey];\n }\n });\n\n //get any field that matches the base language, because it's been translated\n const originPaths = extractWithPath(`..${baseLang}`, translatedFields);\n originPaths.forEach((match) => {\n const origVal = extractWithPath(\n arrayToJSONMatchPath(match.path),\n baseDoc\n )[0].value;\n const translatedVal = extractWithPath(\n arrayToJSONMatchPath(match.path),\n translatedFields\n )[0].value;\n let valToPatch;\n if (typeof translatedVal === 'string') {\n valToPatch = translatedVal;\n } else if (Array.isArray(translatedVal) && translatedVal.length) {\n valToPatch = reconcileArray(\n (origVal as Array<unknown>) ?? [],\n translatedVal\n );\n } else if (\n typeof translatedVal === 'object' &&\n Object.keys(translatedVal as Record<string, unknown>).length\n ) {\n valToPatch = reconcileObject(\n isRecord(origVal) ? origVal : {},\n translatedVal as Record<string, unknown>\n );\n }\n const destinationPath = [\n ...match.path.slice(0, match.path.length - 1), //cut off the \"en\"\n localeId.replace('-', '_'), // replace it with our locale\n ];\n\n merged[arrayToJSONMatchPath(destinationPath)] = valToPatch;\n });\n\n return merged;\n};\n\nconst documentLevelMerge = <\n TTranslatedFields extends Record<string, unknown>,\n TBaseDoc extends SanityDocument,\n>(\n translatedFields: TTranslatedFields,\n //should be fetched according to the revision and id of the translated obj above\n baseDoc: TBaseDoc\n): TBaseDoc & TTranslatedFields => {\n return reconcileObject(\n baseDoc as Record<string, unknown>,\n translatedFields\n ) as TBaseDoc & TTranslatedFields;\n};\n\nexport const BaseDocumentMerger: Merger = {\n fieldLevelMerge,\n documentLevelMerge,\n reconcileArray,\n reconcileObject,\n};\n","import type { SanityDocument } from 'sanity';\n\nexport function getPublishedId(documentId: string): string {\n return documentId.startsWith('drafts.') ? documentId.slice(7) : documentId;\n}\n\nexport function getDocumentPublishedId(document: SanityDocument): string {\n return getPublishedId(document._id);\n}\n\nexport function dedupeDocumentsPreferDraft<T extends SanityDocument>(\n documents: T[]\n): T[] {\n const byPublishedId = new Map<string, T>();\n\n for (const document of documents) {\n const publishedId = getDocumentPublishedId(document);\n const existing = byPublishedId.get(publishedId);\n\n if (!existing || document._id.startsWith('drafts.')) {\n byPublishedId.set(publishedId, document);\n }\n }\n\n return Array.from(byPublishedId.values());\n}\n\nexport function createTranslationStatusKey(\n branchId: string | undefined,\n documentId: string,\n versionId: string,\n localeId: string\n): string {\n const publishedId = getPublishedId(documentId);\n return branchId\n ? `${branchId}:${publishedId}:${versionId}:${localeId}`\n : `${publishedId}:${versionId}:${localeId}`;\n}\n\nexport function createStableTranslationKey(\n branchId: string | undefined,\n documentId: string,\n localeId: string\n): string {\n const publishedId = getPublishedId(documentId);\n return branchId\n ? `${branchId}:${publishedId}:${localeId}`\n : `${publishedId}:${localeId}`;\n}\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { SanityClient, SanityDocument } from 'sanity';\nimport { getPublishedId } from '../../utils/documentIds';\n\n/**\n * Resolves the draft for a document id, falling back to the published copy.\n * Returns `undefined` when neither exists.\n */\nexport const findLatestDraft = (\n documentId: string,\n client: SanityClient\n): Promise<SanityDocument | undefined> => {\n const publishedId = getPublishedId(documentId);\n const query = `*[_id == $id || _id == $draftId]`;\n const params = { id: publishedId, draftId: `drafts.${publishedId}` };\n return client\n .fetch(query, params)\n .then(\n (docs: SanityDocument[]) =>\n docs.find((doc) => doc._id.startsWith('drafts.')) ?? docs[0]\n );\n};\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { SanityClient, SanityDocument } from 'sanity';\n\n//revision fetch\nexport const findDocumentAtRevision = async (\n documentId: string,\n rev: string,\n client: SanityClient\n): Promise<SanityDocument> => {\n const dataset = client.config().dataset;\n const baseUrl = `/data/history/${dataset}/documents/${documentId}?revision=${rev}`;\n const url = client.getUrl(baseUrl);\n const revisionDoc = await fetch(url, { credentials: 'include' })\n .then((req) => req.json())\n .then((req) => {\n if (req.documents && req.documents.length) {\n return req.documents[0];\n }\n return null;\n });\n\n return revisionDoc;\n};\n","import { SanityClient, SanityDocument } from 'sanity';\nimport { createDiagnosticMessage } from 'generaltranslation/internal';\nimport { findLatestDraft } from './findLatestDraft';\nimport { findDocumentAtRevision } from './findDocumentAtRevision';\n\n/**\n * Resolves the document a translation is written against, preferring the\n * revision the translation was produced from and falling back to the latest\n * draft or published copy.\n *\n * Throws when nothing resolves.\n */\nexport async function requireSourceDocument(\n documentId: string,\n versionId: string | undefined,\n client: SanityClient\n): Promise<SanityDocument> {\n let doc: SanityDocument | null | undefined = null;\n\n if (documentId && versionId) {\n doc = await findDocumentAtRevision(documentId, versionId, client);\n }\n if (!doc) {\n doc = await findLatestDraft(documentId, client);\n }\n if (!doc) {\n throw new Error(missingDocumentDiagnostic(documentId));\n }\n\n return doc;\n}\n\n/**\n * Resolves a document that must already exist, without the revision lookup.\n */\nexport async function requireLatestDraft(\n documentId: string,\n client: SanityClient\n): Promise<SanityDocument> {\n const doc = await findLatestDraft(documentId, client);\n if (!doc) {\n throw new Error(missingDocumentDiagnostic(documentId));\n }\n return doc;\n}\n\nfunction missingDocumentDiagnostic(documentId: string): string {\n return createDiagnosticMessage({\n source: 'gt-sanity',\n severity: 'Error',\n whatHappened: 'Could not find the document to translate',\n why: 'no draft or published version of it exists in this dataset',\n fix: 'Check that the document was not deleted, and that the Studio is pointed at the dataset that holds it',\n details: [`Document ID: ${documentId}`],\n });\n}\n","import { JSONPath } from 'jsonpath-plus';\nimport JSONPointer from 'jsonpointer';\nimport type { DedupeFields, FieldMatcher, SkipFields } from '../adapter/types';\n\nexport function forEachMatchingField(\n documentId: string,\n document: Record<string, unknown>,\n fields: FieldMatcher[],\n callback: (result: {\n pointer: string;\n value: unknown;\n parent: Record<string, unknown> | unknown[];\n parentProperty: string;\n }) => void\n): void {\n const applicable = fields.filter(\n (field) =>\n field.documentId === documentId ||\n field.documentId === undefined ||\n field.documentId === null\n );\n\n for (const entry of applicable) {\n if (!entry.fields) continue;\n\n for (const field of entry.fields) {\n const { property, type } = field;\n\n try {\n const results = JSONPath({\n json: document,\n path: property,\n resultType: 'all',\n flatten: true,\n wrap: true,\n });\n\n if (results && results.length > 0) {\n results.forEach(\n (result: {\n pointer: string;\n value: unknown;\n parent: Record<string, unknown> | unknown[];\n parentProperty: string;\n }) => {\n if (type !== undefined) {\n if (\n typeof result.value === 'object' &&\n result.value !== null &&\n !Array.isArray(result.value) &&\n (result.value as Record<string, unknown>)._type === type\n ) {\n callback(result);\n }\n } else {\n callback(result);\n }\n }\n );\n }\n } catch (error) {\n console.warn(`Invalid JSONPath: ${property}`, error);\n }\n }\n }\n}\n\nexport function deleteMatchingFields(\n documentId: string,\n document: Record<string, unknown>,\n fields: FieldMatcher[]\n): void {\n const arrayRemovals: Array<{ parent: unknown[]; index: number }> = [];\n\n forEachMatchingField(documentId, document, fields, (result) => {\n if (Array.isArray(result.parent)) {\n arrayRemovals.push({\n parent: result.parent,\n index: Number(result.parentProperty),\n });\n } else {\n delete result.parent[result.parentProperty];\n }\n });\n\n // Splice array elements in reverse index order to avoid shifting indices\n arrayRemovals.sort((a, b) => b.index - a.index);\n for (const { parent, index } of arrayRemovals) {\n parent.splice(index, 1);\n }\n}\n\nexport function applyDocuments(\n documentId: string,\n sourceDocument: Record<string, unknown>,\n targetDocument: Record<string, unknown>,\n ignore: FieldMatcher[],\n skip: SkipFields[] = [],\n dedupe: DedupeFields[] = [],\n localeId?: string\n) {\n // Deep copy both documents so mutations (e.g. skip-field deletions) never affect the originals\n const mergedDocument = JSON.parse(JSON.stringify(sourceDocument));\n\n // Merge top-level properties of targetDocument\n const clonedTarget = JSON.parse(JSON.stringify(targetDocument));\n for (const [key, value] of Object.entries(clonedTarget)) {\n mergedDocument[key] = value;\n }\n\n // Restore ignored fields from source document\n forEachMatchingField(documentId, sourceDocument, ignore, (result) => {\n JSONPointer.set(mergedDocument, result.pointer, result.value);\n });\n\n // Restore de-duped fields from the source document with a deterministic locale suffix.\n forEachMatchingField(documentId, sourceDocument, dedupe, (result) => {\n JSONPointer.set(\n mergedDocument,\n result.pointer,\n dedupeFieldValue(result.value, localeId)\n );\n });\n\n // Remove skip fields from merged document\n deleteMatchingFields(documentId, mergedDocument, skip);\n\n return mergedDocument;\n}\n\nfunction dedupeFieldValue(value: unknown, localeId?: string): unknown {\n if (!localeId) return value;\n\n if (typeof value === 'string') {\n return appendLocaleSuffix(value, localeId);\n }\n\n if (\n value &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n typeof (value as Record<string, unknown>).current === 'string'\n ) {\n const slug = value as Record<string, unknown>;\n return {\n ...slug,\n current: appendLocaleSuffix(slug.current as string, localeId),\n };\n }\n\n return value;\n}\n\nfunction appendLocaleSuffix(value: string, localeId: string): string {\n if (!value) return value;\n\n const suffix = createLocaleSuffix(localeId);\n if (!suffix || value.endsWith(suffix)) return value;\n\n return `${value}${suffix}`;\n}\n\nfunction createLocaleSuffix(localeId: string): string {\n const normalized = localeId\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n\n return normalized ? `-${normalized}` : '';\n}\n","export function randomKey(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n","/**\n * GROQ fragments for reading `translation.metadata` documents, single-sourced\n * so every query stays in sync with the write path\n * (`createI18nDocAndPatchMetadata` / `getOrCreateTranslationMetadata`).\n *\n * The locale of each `translations[]` entry lives in its literal `language`\n * property. That is the storage shape of the metadata document itself and is\n * unrelated to the configurable `languageField` option, which only renames\n * the language field on content documents.\n */\nexport const TRANSLATION_METADATA_TYPE = 'translation.metadata';\n\n/** Deterministic metadata document id for a source document. */\nexport function translationMetadataId(publishedDocumentId: string): string {\n return `${TRANSLATION_METADATA_TYPE}.${publishedDocumentId}`;\n}\n\n/**\n * `translations[]` entries whose `language` matches a GROQ condition, e.g.\n * `metadataTranslations('== $sourceLocale')` or\n * `metadataTranslations('in $localeIds', 'defined(value._ref)')`.\n */\nexport function metadataTranslations(\n languageCondition: string,\n extraCondition?: string\n): string {\n return `translations[language ${languageCondition}${\n extraCondition ? ` && ${extraCondition}` : ''\n }]`;\n}\n\n/**\n * The `_ref` of the document recorded for a language, e.g.\n * `metadataTranslationRef('$sourceLocale')`.\n */\nexport function metadataTranslationRef(languageExpression: string): string {\n return `${metadataTranslations(`== ${languageExpression}`)}[0].value._ref`;\n}\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { SanityClient, SanityDocumentLike } from 'sanity';\nimport { pluginConfig } from '../../../adapter/core';\nimport { applyDocuments } from '../../../utils/applyDocuments';\nimport { getPublishedId } from '../../../utils/documentIds';\nimport { randomKey } from '../../../utils/randomKey';\nimport { metadataTranslations } from '../../../utils/translationMetadata';\n\nexport async function createI18nDocAndPatchMetadata(\n sourceDocument: SanityDocumentLike,\n translatedDoc: SanityDocumentLike,\n localeId: string,\n client: SanityClient,\n translationMetadata: SanityDocumentLike,\n sourceDocumentId: string,\n languageField: string = 'language'\n): Promise<void> {\n const publishedSourceDocumentId = getPublishedId(sourceDocumentId);\n translatedDoc[languageField] = localeId;\n const translations = translationMetadata.translations as Record<\n string,\n unknown\n >[];\n const existingLocaleKey = translations.find(\n (translation) => translation.language === localeId\n );\n const operation = existingLocaleKey ? 'replace' : 'after';\n const location = existingLocaleKey\n ? metadataTranslations(`== \"${localeId}\"`)\n : 'translations[-1]';\n\n //remove system fields\n const { _updatedAt, _createdAt, ...rest } = translatedDoc;\n\n const appliedDocument = applyDocuments(\n publishedSourceDocumentId,\n sourceDocument,\n rest,\n pluginConfig.getIgnoreFields(),\n pluginConfig.getSkipFields(),\n pluginConfig.getDedupeFields(),\n localeId\n );\n\n // Check if this is a singleton document and apply singleton mapping\n const singletons = pluginConfig.getSingletons();\n const isSingleton = singletons.includes(publishedSourceDocumentId);\n\n let createDocumentPromise;\n if (isSingleton) {\n const singletonMapping = pluginConfig.getSingletonMapping();\n const translatedDocId = singletonMapping(\n publishedSourceDocumentId,\n localeId\n );\n createDocumentPromise = client.create({\n ...appliedDocument,\n _type: rest._type,\n _id: `drafts.${translatedDocId}`,\n });\n } else {\n createDocumentPromise = client.create({\n ...appliedDocument,\n _type: rest._type,\n _id: 'drafts.',\n });\n }\n\n const doc = await createDocumentPromise;\n const _ref = getPublishedId(doc._id);\n await client\n .transaction()\n .patch(translationMetadata._id, (p) =>\n p.insert(operation, location, [\n {\n _key: randomKey(),\n language: localeId,\n _type: 'internationalizedArrayReferenceValue',\n value: {\n _type: 'reference',\n _ref,\n _weak: true,\n _strengthenOnPublish: {\n type: doc._type,\n },\n },\n },\n ])\n )\n .commit();\n}\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport {\n KeyedObject,\n Reference,\n SanityClient,\n SanityDocumentLike,\n} from 'sanity';\nimport { randomKey } from '../../../utils/randomKey';\nimport { getPublishedId } from '../../../utils/documentIds';\nimport {\n metadataTranslationRef,\n translationMetadataId,\n TRANSLATION_METADATA_TYPE,\n} from '../../../utils/translationMetadata';\n\ntype TranslationReference = KeyedObject & {\n _type: 'internationalizedArrayReferenceValue';\n value: Reference;\n};\n\nexport const getOrCreateTranslationMetadata = async (\n documentId: string,\n baseDocument: SanityDocumentLike,\n client: SanityClient,\n baseLanguage: string\n): Promise<SanityDocumentLike> => {\n const publishedId = getPublishedId(documentId);\n\n // First, try to get existing metadata\n const existingMetadata = await client.fetch(\n `*[\n _type == '${TRANSLATION_METADATA_TYPE}' &&\n ${metadataTranslationRef('$baseLanguage')} == $id\n ][0]`,\n { baseLanguage, id: publishedId }\n );\n\n if (existingMetadata) {\n return existingMetadata;\n }\n\n // If no metadata exists, create it atomically\n const baseLangEntry: TranslationReference = {\n _key: randomKey(),\n language: baseLanguage,\n _type: 'internationalizedArrayReferenceValue',\n value: {\n _type: 'reference',\n _ref: getPublishedId(baseDocument._id),\n },\n };\n\n if (baseDocument._id.startsWith('drafts.')) {\n baseLangEntry.value = {\n ...baseLangEntry.value,\n _weak: true,\n //this should reflect doc i18n config when this\n //plugin is able to take that as a config option\n _strengthenOnPublish: {\n type: baseDocument._type,\n },\n };\n }\n\n try {\n // Use createIfNotExists to handle race conditions\n return await client.createIfNotExists({\n _id: translationMetadataId(publishedId),\n _type: TRANSLATION_METADATA_TYPE,\n translations: [baseLangEntry],\n });\n } catch (error) {\n // If creation fails due to race condition, fetch the existing document\n const metadata = await client.fetch(\n `*[\n _type == '${TRANSLATION_METADATA_TYPE}' &&\n ${metadataTranslationRef('$baseLanguage')} == $id\n ][0]`,\n { baseLanguage, id: publishedId }\n );\n\n if (metadata) {\n return metadata;\n }\n\n throw error;\n }\n};\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { SanityClient, SanityDocumentLike } from 'sanity';\nimport JSONPointer from 'jsonpointer';\nimport {\n applyDocuments,\n deleteMatchingFields,\n forEachMatchingField,\n} from '../../../utils/applyDocuments';\nimport { pluginConfig } from '../../../adapter/core';\nimport { getPublishedId } from '../../../utils/documentIds';\n\nconst SYSTEM_FIELDS = ['_id', '_rev', '_updatedAt', 'language'];\n\nconst isSystemField = (field: string) => SYSTEM_FIELDS.includes(field);\n\nexport async function patchI18nDoc(\n sourceDocumentId: string,\n i18nDocId: string,\n sourceDocument: SanityDocumentLike,\n mergedDocument: SanityDocumentLike,\n translatedFields: Record<string, unknown>,\n client: SanityClient,\n existingDocument?: SanityDocumentLike\n): Promise<void> {\n const cleanedMerge: Record<string, unknown> = {};\n Object.entries(mergedDocument).forEach(([key, value]) => {\n if (\n //only patch those fields that had translated strings\n key in translatedFields &&\n //don't overwrite any existing system values on the i18n doc\n !isSystemField(key)\n ) {\n cleanedMerge[key] = value;\n }\n });\n const cleanedSourceDocument: Record<string, unknown> = {};\n Object.entries(sourceDocument).forEach(([key, value]) => {\n if (\n // extract only the fields that are not system fields\n !isSystemField(key)\n ) {\n cleanedSourceDocument[key] = value;\n }\n });\n const appliedDocument = applyDocuments(\n sourceDocumentId,\n cleanedSourceDocument,\n cleanedMerge,\n pluginConfig.getIgnoreFields(),\n pluginConfig.getSkipFields()\n );\n const dedupeFields = pluginConfig.getDedupeFields();\n deleteMatchingFields(sourceDocumentId, appliedDocument, dedupeFields);\n if (existingDocument) {\n forEachMatchingField(\n sourceDocumentId,\n existingDocument,\n dedupeFields,\n (result) => {\n JSONPointer.set(appliedDocument, result.pointer, result.value);\n }\n );\n }\n if (i18nDocId.startsWith('drafts.')) {\n await client.patch(i18nDocId, { set: appliedDocument }).commit();\n return;\n }\n\n // A draft in Sanity is just a document whose id carries a `drafts.` prefix,\n // and the client writes to whatever id it is handed β€” it will not redirect a\n // write to the draft on your behalf. A published id here is therefore the\n // copy readers are served. Copy it into a draft and patch that, so the\n // translation lands somewhere reviewable and the live document only changes\n // when someone publishes.\n const seed = existingDocument ?? (await client.getDocument(i18nDocId));\n if (!seed) {\n // References in `translation.metadata` are weak, so they outlive the\n // documents they point at: deleting a translation leaves its entry behind.\n // With no document to copy there is nothing to seed a draft from, so patch\n // the id directly and let the missing document surface as an error.\n await client.patch(i18nDocId, { set: appliedDocument }).commit();\n return;\n }\n\n const draftId = `drafts.${getPublishedId(i18nDocId)}`;\n await client\n .transaction()\n .createIfNotExists({ ...seed, _id: draftId })\n .patch(draftId, (patch) => patch.set(appliedDocument))\n .commit();\n}\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { SanityClient, SanityDocument, SanityDocumentLike } from 'sanity';\nimport { BaseDocumentMerger } from '../../serialization/BaseDocumentMerger';\n\nimport { findLatestDraft } from '../utils/findLatestDraft';\nimport { requireSourceDocument } from '../utils/requireSourceDocument';\nimport { createI18nDocAndPatchMetadata } from './helpers/createI18nDocAndPatchMetadata';\nimport { getOrCreateTranslationMetadata } from './helpers/getOrCreateTranslationMetadata';\nimport { patchI18nDoc } from './helpers/patchI18nDoc';\nimport type { GTFile } from '../../types';\nimport { pluginConfig } from '../../adapter/core';\n\ntype TranslationReference = {\n language?: string;\n value?: {\n _ref?: string;\n };\n};\n\nexport const documentLevelPatch = async (\n docInfo: GTFile,\n translatedFields: SanityDocument,\n localeId: string,\n client: SanityClient,\n languageField: string = 'language',\n mergeWithTargetLocale: boolean = false\n): Promise<void> => {\n const baseLanguage = pluginConfig.getSourceLocale();\n\n //this is the document that will serve as the translated doc\n let i18nDoc: SanityDocument | undefined;\n\n /*\n * we send over the _rev with our translation file so we can\n * accurately coalesce the translations in case something has\n * changed in the base document since translating\n */\n //this is the document we use to merge with the translated fields\n let baseDoc = await requireSourceDocument(\n docInfo.documentId,\n docInfo.versionId,\n client\n );\n\n /* first, check our metadata to see if a translated document exists\n * if no metadata exists, we create it atomically\n */\n const translationMetadata = await getOrCreateTranslationMetadata(\n docInfo.documentId,\n baseDoc,\n client,\n baseLanguage\n );\n\n //the id of the translated document should be on the metadata if it exists\n const translations =\n translationMetadata.translations as TranslationReference[];\n const i18nDocId = translations.find(\n (translation) => translation.language === localeId\n )?.value?._ref;\n\n if (i18nDocId) {\n //get draft or published\n i18nDoc = await findLatestDraft(i18nDocId, client);\n }\n\n //if the user has chosen to merge with the target locale,\n //any existing target document will serve as our base document\n if (mergeWithTargetLocale && i18nDoc) {\n baseDoc = i18nDoc;\n } else if (docInfo.documentId && docInfo.versionId) {\n /*\n * we send over the _rev with our translation file so we can\n * accurately coalesce the translations in case something has\n * changed in the base document since translating\n */\n baseDoc = await requireSourceDocument(\n docInfo.documentId,\n docInfo.versionId,\n client\n );\n }\n /*\n * we then merge the translation with the base document\n * to create a document that contains the translation and everything\n * that wasn't sent over for translation\n */\n const merged = BaseDocumentMerger.documentLevelMerge(\n translatedFields,\n baseDoc\n ) as SanityDocumentLike;\n\n if (i18nDoc) {\n await patchI18nDoc(\n docInfo.documentId,\n i18nDoc._id,\n baseDoc,\n merged,\n translatedFields,\n client,\n i18nDoc\n );\n }\n //otherwise, create a new document\n //and add the document reference to the metadata document\n else {\n const freshTranslationMetadata = await getOrCreateTranslationMetadata(\n docInfo.documentId,\n baseDoc,\n client,\n baseLanguage\n );\n const freshTranslations =\n freshTranslationMetadata.translations as TranslationReference[];\n const freshI18nDocId = freshTranslations.find(\n (translation) => translation.language === localeId\n )?.value?._ref;\n\n const freshI18nDoc = freshI18nDocId\n ? await findLatestDraft(freshI18nDocId, client)\n : undefined;\n\n if (freshI18nDoc) {\n await patchI18nDoc(\n docInfo.documentId,\n freshI18nDoc._id,\n baseDoc,\n merged,\n translatedFields,\n client,\n freshI18nDoc\n );\n return;\n }\n\n /*\n * A metadata entry for this locale can outlive the document it points at.\n * Since the references are weak, deleting a translation leaves the entry\n * behind.\n *\n * `createI18nDocAndPatchMetadata` replaces the existing entry for the\n * locale.\n */\n await createI18nDocAndPatchMetadata(\n baseDoc,\n merged,\n localeId,\n client,\n freshTranslationMetadata,\n docInfo.documentId,\n languageField\n );\n }\n};\n","// Helpers for recognising the `sanity-plugin-internationalized-array` storage\n// shape, where a localized field is stored as an array of per-locale items:\n//\n// title: [\n// { _key: 'abc', _type: 'internationalizedArrayStringValue', language: 'en', value: 'Hello' },\n// { _key: 'def', _type: 'internationalizedArrayStringValue', language: 'es', value: 'Hola' },\n// ]\n//\n// Detection is shape-based (not schema-based) so the serializer/merger do not\n// have to thread the schema through every call, but it is anchored on the\n// value `_type` naming convention (`internationalizedArray…Value`) so\n// user-defined types that merely share the `{ language, value }` shape are\n// not misdetected. The prefix is fixed by sanity-plugin-internationalized-array.\nconst TYPE_PREFIX = 'internationalizedArray';\n\nexport const isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nexport type InternationalizedArrayItem = {\n _key?: string;\n _type: string;\n language: string;\n value: unknown;\n};\n\n/**\n * A single `{ _key, _type, language, value }` entry. The `_type` of the\n * generated value objects is always `internationalizedArray<FieldType>Value`\n * (e.g. `internationalizedArrayStringValue`), so both the prefix and the\n * `Value` suffix are required β€” a bare `endsWith('Value')` check would\n * misdetect user-defined types like `priceValue` that happen to carry\n * `language`/`value` keys.\n */\nexport function isInternationalizedArrayItem(\n item: unknown\n): item is InternationalizedArrayItem {\n return (\n isRecord(item) &&\n typeof item._type === 'string' &&\n item._type.startsWith(TYPE_PREFIX) &&\n item._type.endsWith('Value') &&\n typeof item.language === 'string' &&\n 'value' in item\n );\n}\n\n/**\n * A non-empty array where every element is an internationalized-array item.\n */\nexport function isInternationalizedArrayField(\n value: unknown\n): value is InternationalizedArrayItem[] {\n return (\n Array.isArray(value) &&\n value.length > 0 &&\n value.every(isInternationalizedArrayItem)\n );\n}\n\n/**\n * Returns the item for a given locale, matching on the exact `language` id\n * (hyphens preserved, e.g. `fr-CA`). Never matches on `_key`, which is random.\n */\nexport function findLocaleItem(\n field: InternationalizedArrayItem[],\n locale: string\n): InternationalizedArrayItem | undefined {\n return field.find((item) => item.language === locale);\n}\n\n/**\n * Whether any internationalized-array field anywhere in the value has an item\n * for the given locale. Used to skip locales with no existing content instead\n * of uploading an empty translation.\n */\nexport function hasLocaleContent(value: unknown, locale: string): boolean {\n if (isInternationalizedArrayField(value)) {\n return findLocaleItem(value, locale) !== undefined;\n }\n\n if (Array.isArray(value)) {\n return value.some((item) => hasLocaleContent(item, locale));\n }\n\n if (isRecord(value)) {\n return Object.values(value).some((item) => hasLocaleContent(item, locale));\n }\n\n return false;\n}\n","import { randomKey } from '../../utils/randomKey';\nimport {\n findLocaleItem,\n InternationalizedArrayItem,\n isInternationalizedArrayField,\n isRecord,\n} from './detect';\n\n/**\n * Upsert the translated value for `targetLocale` into an internationalized\n * array, preserving every other locale item and its (random) `_key`.\n *\n * Sanity mutations can only address array items by `_key`, and `_key` is random\n * here, so we resolve the target item by its `language` field and reuse its\n * existing `_key`; if absent we append a fresh random `_key`.\n */\nfunction upsertLocaleItem(\n baseArray: InternationalizedArrayItem[],\n translatedValue: unknown,\n targetLocale: string,\n sourceLocale: string\n): InternationalizedArrayItem[] {\n const itemType = (findLocaleItem(baseArray, sourceLocale) ?? baseArray[0])\n ._type;\n\n const updated = baseArray.map((item) =>\n item.language === targetLocale\n ? { ...item, value: translatedValue }\n : { ...item }\n );\n\n if (!findLocaleItem(updated, targetLocale)) {\n updated.push({\n _key: randomKey(),\n _type: itemType,\n language: targetLocale,\n value: translatedValue,\n });\n }\n\n return updated;\n}\n\n/**\n * Merge a single base value with its translated counterpart, returning the new\n * value to write, or `undefined` when nothing localized changed at this level.\n * Recurses through plain objects (by key) and plain arrays (by `_key`) so\n * internationalized-array fields nested inside other content are also handled.\n */\nfunction mergeValue(\n baseValue: unknown,\n translatedValue: unknown,\n targetLocale: string,\n sourceLocale: string\n): unknown {\n if (isInternationalizedArrayField(baseValue)) {\n return upsertLocaleItem(\n baseValue,\n translatedValue,\n targetLocale,\n sourceLocale\n );\n }\n\n if (Array.isArray(baseValue) && Array.isArray(translatedValue)) {\n let changed = false;\n const merged = baseValue.map((item) => {\n if (!isRecord(item) || typeof item._key !== 'string') {\n return item;\n }\n const translatedItem = translatedValue.find(\n (candidate) => isRecord(candidate) && candidate._key === item._key\n );\n if (!translatedItem) {\n return item;\n }\n const mergedItem = mergeValue(\n item,\n translatedItem,\n targetLocale,\n sourceLocale\n );\n if (mergedItem !== undefined) {\n changed = true;\n return mergedItem;\n }\n return item;\n });\n return changed ? merged : undefined;\n }\n\n if (isRecord(baseValue) && isRecord(translatedValue)) {\n let changed = false;\n const merged: Record<string, unknown> = { ...baseValue };\n for (const key of Object.keys(translatedValue)) {\n if (key.startsWith('_') || !(key in baseValue)) {\n continue;\n }\n const mergedChild = mergeValue(\n baseValue[key],\n translatedValue[key],\n targetLocale,\n sourceLocale\n );\n if (mergedChild !== undefined) {\n merged[key] = mergedChild;\n changed = true;\n }\n }\n return changed ? merged : undefined;\n }\n\n return undefined;\n}\n\n/**\n * Compare a base Sanity document against a deserialized translation and produce\n * a patch object of top-level fields whose internationalized-array content\n * changed. Each entry is the full merged top-level value (with the target\n * locale upserted), suitable for `client.patch(id).set(changes)`.\n *\n * Only top-level fields that actually changed are returned, so unrelated\n * content and other locales are left untouched.\n */\nexport function mergeInternationalizedArrays(\n baseDoc: Record<string, unknown>,\n translatedFields: Record<string, unknown>,\n targetLocale: string,\n sourceLocale: string\n): Record<string, unknown> {\n const changes: Record<string, unknown> = {};\n\n for (const key of Object.keys(translatedFields)) {\n if (key.startsWith('_') || !(key in baseDoc)) {\n continue;\n }\n const merged = mergeValue(\n baseDoc[key],\n translatedFields[key],\n targetLocale,\n sourceLocale\n );\n if (merged !== undefined) {\n changes[key] = merged;\n }\n }\n\n return changes;\n}\n","import { SanityClient, SanityDocument } from 'sanity';\nimport { pluginConfig } from '../../adapter/core';\nimport { mergeInternationalizedArrays } from '../../serialization/internationalizedArray/merge';\nimport type { GTFile } from '../../types';\nimport { getPublishedId } from '../../utils/documentIds';\nimport { findLatestDraft } from '../utils/findLatestDraft';\n\n/**\n * Import a translated internationalized-array document in place.\n *\n * Unlike document-level import (which creates per-locale documents and tracks\n * translation metadata), array localization upserts the target-locale `value`\n * into the same source document. We read the latest draft so concurrent edits\n * to the source are not clobbered, merge only the changed top-level fields, and\n * commit a single patch.\n */\nexport const internationalizedArrayPatch = async (\n docInfo: GTFile,\n translatedFields: SanityDocument,\n localeId: string,\n client: SanityClient\n): Promise<void> => {\n const sourceLocale = pluginConfig.getSourceLocale();\n\n const baseDoc = await findLatestDraft(docInfo.documentId, client);\n if (!baseDoc) {\n return;\n }\n\n const changes = mergeInternationalizedArrays(\n baseDoc as Record<string, unknown>,\n translatedFields as Record<string, unknown>,\n localeId,\n sourceLocale\n );\n\n if (Object.keys(changes).length === 0) {\n return;\n }\n\n // Every key in `changes` already exists on the base document (merge only\n // returns existing fields), so a full `set` of the merged field is safe and\n // preserves all other locale items and their random `_key`s.\n if (baseDoc._id.startsWith('drafts.')) {\n await client.patch(baseDoc._id).set(changes).commit();\n return;\n }\n\n // Only the published document exists. Mutations via the client write to the\n // exact id given (drafts are a Studio convention, not created server-side),\n // so patch a draft seeded from the published state instead of publishing\n // translated content directly.\n const draftId = `drafts.${getPublishedId(baseDoc._id)}`;\n await client\n .transaction()\n .createIfNotExists({ ...baseDoc, _id: draftId })\n .patch(draftId, (patch) => patch.set(changes))\n .commit();\n};\n","// Adapted from https://github.com/sanity-io/sanity-naive-html-serializer\nimport { htmlToBlocks } from '@portabletext/block-tools';\nimport { Schema } from '@sanity/schema';\nimport { ObjectField, PortableTextSpan, PortableTextTextBlock } from 'sanity';\n\nconst defaultSchema = Schema.compile({\n name: 'default',\n types: [\n {\n type: 'object',\n name: 'default',\n fields: [\n {\n name: 'block',\n type: 'array',\n of: [{ type: 'block' }],\n },\n ],\n },\n ],\n});\n\nexport const blockContentType = defaultSchema\n .get('default')\n .fields.find((field: ObjectField) => field.name === 'block').type;\n\nexport const noSchemaWarning = (obj: Element): string =>\n `WARNING: Unfortunately the deserializer may have issues with this field or object: ${obj.className}.\n If it's a specific type, you may need to declare at the top level, or write a custom deserializer.`;\n\n//helper to handle messy input -- take advantage\n//of blockTools' sanitizing behavior for single strings\nexport const preprocess = (html: string): string => {\n const intermediateBlocks = htmlToBlocks(\n `<p>${html}</p>`,\n blockContentType\n ) as PortableTextTextBlock<PortableTextSpan>[];\n if (!intermediateBlocks.length) {\n throw new Error(`Error parsing string '${html}'`);\n }\n return intermediateBlocks[0].children[0].text;\n};\n","export function attachGTData(\n html: string,\n data: Record<string, unknown>,\n type: 'markDef'\n): string {\n // Parse the HTML string to find the first element\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n const firstElement = doc.body.firstElementChild;\n\n if (!firstElement) {\n // If no element found, return original HTML\n return html;\n }\n\n // Encode the data as base64 JSON\n const encodedData = encode(JSON.stringify({ [type]: data }));\n\n // Add the data-gt-internal attribute\n firstElement.setAttribute('data-gt-internal', encodedData);\n\n return firstElement.outerHTML;\n}\n\nexport function detachGTData(html: string): {\n html: string;\n data?: Record<'markDef', Record<string, unknown>>;\n} {\n // Parse the HTML string to find the first element\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n const firstElement = doc.body.firstElementChild;\n\n if (!firstElement) {\n // If no element found, return original HTML with no data\n return { html };\n }\n\n // Get the encoded data\n const encodedData = firstElement.getAttribute('data-gt-internal');\n\n let extractedData: Record<'markDef', Record<string, unknown>> | undefined;\n if (encodedData) {\n try {\n // Decode and parse the data\n const decodedData = decode(encodedData);\n extractedData = JSON.parse(decodedData);\n\n // Remove the data attribute to clean up the HTML\n firstElement.removeAttribute('data-gt-internal');\n } catch (error) {\n console.warn('Failed to decode GT internal data:', error);\n }\n }\n\n return {\n html: firstElement.outerHTML,\n data: extractedData,\n };\n}\n\n// Encode a string to base64\nexport function encode(data: string): string {\n // Browser path\n const bytes = new TextEncoder().encode(data);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n// Decode a base64 string to a string\nexport function decode(base64: string): string {\n // Browser path\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new TextDecoder().decode(bytes);\n}\n","// Adapted from https://github.com/sanity-io/sanity-naive-html-serializer\n\nimport type { PortableTextBlockStyle } from '@portabletext/types';\n\nimport {\n PortableTextBlockComponent,\n PortableTextListComponent,\n PortableTextListItemComponent,\n PortableTextMarkComponent,\n PortableTextHtmlComponents,\n} from '@portabletext/to-html';\n\nimport { htmlToBlocks } from '@portabletext/block-tools';\nimport { blockContentType } from './deserialize/helpers';\nimport { PortableTextObject, PortableTextTextBlock, TypedObject } from 'sanity';\nimport { detachGTData } from './data';\nimport type { CustomDeserializers } from './types';\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nexport const defaultStopTypes = [\n 'reference',\n 'date',\n 'datetime',\n 'file',\n 'geopoint',\n 'image',\n 'number',\n 'crop',\n 'hotspot',\n 'boolean',\n 'url',\n 'color',\n 'code',\n];\n\nexport const defaultMarks: Record<string, PortableTextMarkComponent> = {};\n\nexport const defaultPortableTextBlockStyles: Record<\n PortableTextBlockStyle,\n PortableTextBlockComponent | undefined\n> = {\n normal: ({ value, children }) => `<p id=\"${value._key}\">${children}</p>`,\n blockquote: ({ value, children }) =>\n `<blockquote id=\"${value._key}\">${children}</blockquote>`,\n h1: ({ value, children }) => `<h1 id=\"${value._key}\">${children}</h1>`,\n h2: ({ value, children }) => `<h2 id=\"${value._key}\">${children}</h2>`,\n h3: ({ value, children }) => `<h3 id=\"${value._key}\">${children}</h3>`,\n h4: ({ value, children }) => `<h4 id=\"${value._key}\">${children}</h4>`,\n h5: ({ value, children }) => `<h5 id=\"${value._key}\">${children}</h5>`,\n h6: ({ value, children }) => `<h6 id=\"${value._key}\">${children}</h6>`,\n};\n\nconst defaultLists: Record<'number' | 'bullet', PortableTextListComponent> = {\n number: ({ value, children }) =>\n `<ol id=\"${value._key.replace('-parent', '')}\">${children}</ol>`,\n bullet: ({ value, children }) =>\n `<ul id=\"${value._key.replace('-parent', '')}\">${children}</ul>`,\n};\n\nconst defaultListItem: PortableTextListItemComponent = ({\n value,\n children,\n}) => {\n const { _key, level } = value;\n return `<li id=\"${(_key || '').replace('-parent', '')}\" data-level=\"${level}\">${children}</li>`;\n};\n\nconst unknownBlockFunc: PortableTextBlockComponent = ({ value, children }) =>\n `<p id=\"${value._key}\" data-type=\"unknown-block-style\" data-style=\"${value.style}\">${children}</p>`;\n\nexport const customSerializers: Partial<PortableTextHtmlComponents> = {\n unknownType: ({ value }) => `<div class=\"${value._type}\"></div>`,\n types: {},\n marks: defaultMarks,\n block: defaultPortableTextBlockStyles,\n list: defaultLists,\n listItem: defaultListItem,\n unknownBlockStyle: unknownBlockFunc,\n};\n\nexport const customDeserializers: CustomDeserializers = { types: {} };\n\nexport const customBlockDeserializers: Array<unknown> = [\n // handle marks with data-gt-internal\n {\n deserialize(\n node: Node,\n next: (\n elements: Node | Node[] | NodeList\n ) => TypedObject | TypedObject[] | undefined\n ): PortableTextTextBlock | TypedObject | undefined {\n if (node.nodeType !== 1) {\n return undefined;\n }\n const el = node as HTMLElement;\n if (!el.hasChildNodes()) {\n return undefined;\n }\n\n if (!el.getAttribute('data-gt-internal')) {\n return undefined;\n }\n\n const { html, data } = detachGTData(el.outerHTML);\n const block = htmlToBlocks(html, blockContentType)[0];\n\n const children = next(el.childNodes);\n\n let markDefs: PortableTextObject[] = [];\n if ('markDefs' in block) {\n markDefs = (block.markDefs as PortableTextObject[]) ?? [];\n }\n if (data?.markDef) {\n markDefs.push(data.markDef as PortableTextObject);\n }\n if (Array.isArray(children)) {\n children.forEach((child) => {\n if (!isRecord(child)) {\n return;\n }\n const marks = Array.isArray(child.marks) ? child.marks : [];\n child.marks = data?.markDef?._key\n ? [...marks, data.markDef._key]\n : marks;\n });\n }\n // Resolve marks in the child nodes\n const output = {\n ...block,\n markDefs,\n children,\n };\n return output;\n },\n },\n //handle undeclared styles\n {\n deserialize(\n node: Node,\n next: (\n elements: Node | Node[] | NodeList\n ) => TypedObject | TypedObject[] | undefined\n ): PortableTextTextBlock | TypedObject | undefined {\n if (node.nodeType !== 1) {\n return undefined;\n }\n const el = node as HTMLElement;\n if (!el.hasChildNodes()) {\n return undefined;\n }\n\n if (el.getAttribute('data-type') !== 'unknown-block-style') {\n return undefined;\n }\n\n const style = el.getAttribute('data-style') ?? '';\n const block = htmlToBlocks(el.outerHTML, blockContentType)[0];\n\n return {\n ...block,\n style,\n children: next(el.childNodes),\n };\n },\n },\n //handle list items\n {\n deserialize(\n node: Node,\n next: (\n elements: Node | Node[] | NodeList\n ) => TypedObject | TypedObject[] | undefined\n ): PortableTextTextBlock | TypedObject | undefined {\n if (node.nodeType !== 1) {\n return undefined;\n }\n const el = node as HTMLElement;\n if (!el.hasChildNodes()) {\n return undefined;\n }\n\n if (el.tagName.toLowerCase() !== 'li') {\n return undefined;\n }\n\n const tagsToStyle: Record<string, string> = {\n ul: 'bullet',\n ol: 'number',\n };\n\n const parent = el.parentNode as HTMLUListElement | HTMLOListElement;\n if (!parent || !parent.tagName) {\n return undefined;\n }\n\n const listItem = tagsToStyle[parent.tagName.toLowerCase()];\n if (!listItem) {\n return undefined;\n }\n\n const level =\n el.getAttribute('data-level') &&\n parseInt(el.getAttribute('data-level') || '0', 10);\n const _key = el.id;\n let block = htmlToBlocks(parent.outerHTML, blockContentType)[0];\n const customStyle = el.children?.[0]?.getAttribute('data-style');\n\n //check if the object inside is also serialized -- that means it has a style\n //or custom annotation and we should use childNode serialization\n const regex = new RegExp(/<(\"[^\"]*\"|'[^']*'|[^'\">])*>/);\n if (regex.test(el.innerHTML)) {\n const newBlock = htmlToBlocks(el.innerHTML, blockContentType)[0];\n if (newBlock) {\n block = {\n ...block,\n ...newBlock,\n // @ts-ignore\n style: customStyle ?? (newBlock as PortableTextTextBlock).style,\n };\n\n //next(childNodes) plays poorly with custom styles, issue to be filed.\n if (customStyle) {\n return block as PortableTextTextBlock;\n }\n }\n }\n\n return {\n ...block,\n level,\n _key,\n listItem,\n children: next(el.childNodes),\n };\n },\n },\n];\n","import { PortableTextTextBlock } from 'sanity';\n\n// Helper function to merge multiple blocks\n// Prioritize blocks[0]\nexport function mergeBlocks(blocks: PortableTextTextBlock[]) {\n const mergedBlock = { ...blocks[0] };\n mergedBlock.markDefs = mergedBlock.markDefs ?? [];\n for (const [idx, block] of blocks.entries()) {\n if (idx === 0) {\n continue;\n }\n mergedBlock.children.push(...block.children);\n mergedBlock.markDefs.push(...(block.markDefs ?? []));\n }\n mergedBlock._type = 'block';\n\n return mergedBlock;\n}\n","// Adapted from https://github.com/sanity-io/sanity-naive-html-serializer\nimport { htmlToBlocks } from '@portabletext/block-tools';\nimport {\n customDeserializers,\n customBlockDeserializers,\n} from '../BaseSerializationConfig';\nimport { CustomDeserializers, Deserializer } from '../types';\nimport { blockContentType, preprocess } from './helpers';\nimport { mergeBlocks } from '../helpers';\n\nexport const deserializeArray = (\n arrayHTML: Element,\n deserializers: CustomDeserializers = customDeserializers,\n blockDeserializers: Array<unknown> = customBlockDeserializers\n) => {\n const output: unknown[] = [];\n const children = Array.from(arrayHTML.children);\n children.forEach((child) => {\n let deserializedObject: unknown;\n try {\n if (child.tagName?.toLowerCase() === 'span') {\n deserializedObject = preprocess(child.innerHTML);\n }\n //has specific class name or data type, so it's an obj\n else if (\n child.className ||\n child.getAttribute('data-type') === 'object'\n ) {\n deserializedObject = deserializeObject(\n child,\n deserializers,\n blockDeserializers\n );\n if (\n deserializedObject &&\n typeof deserializedObject === 'object' &&\n !Array.isArray(deserializedObject)\n ) {\n (deserializedObject as Record<string, unknown>)._key = child.id;\n }\n } else {\n const blocks = htmlToBlocks(child.outerHTML, blockContentType, {\n rules: blockDeserializers as NonNullable<\n Parameters<typeof htmlToBlocks>[2]\n >['rules'],\n });\n deserializedObject = mergeBlocks(\n blocks as unknown as Parameters<typeof mergeBlocks>[0]\n );\n (deserializedObject as Record<string, unknown>)._key = child.id;\n }\n } catch (e) {\n //eslint-disable-next-line no-console\n console.debug(\n `Tried to deserialize block: ${child.outerHTML} in an array but failed to identify it! Error: ${e}`\n );\n }\n output.push(deserializedObject);\n });\n return output;\n};\n\nexport const deserializeObject = (\n objectHTML: Element,\n deserializers: CustomDeserializers = customDeserializers,\n blockDeserializers: Array<unknown> = customBlockDeserializers\n) => {\n const deserialize = deserializers.types?.[objectHTML.className];\n if (deserialize) {\n return deserialize(objectHTML as HTMLElement);\n }\n\n const output: Record<string, unknown> = {};\n //account for anonymous inline objects\n if (objectHTML.className) {\n output._type = objectHTML.className;\n }\n const children = Array.from(objectHTML.children);\n\n children.forEach((child) => {\n //string field\n if (child.tagName?.toLowerCase() === 'span') {\n output[child.className] = preprocess(child.innerHTML);\n }\n //richer field, either object or array\n else if (child.getAttribute('data-level') === 'field') {\n const deserialized = deserializeHTML(\n child.outerHTML,\n deserializers,\n blockDeserializers\n );\n if (deserialized && Object.keys(deserialized).length) {\n output[child.className] = deserialized;\n } else {\n //eslint-disable-next-line no-console\n console.debug(\n `Deserializer: Skipping empty or unreadable HTML: ${child.outerHTML}`\n );\n }\n } else if (child.getAttribute('data-type') === 'array') {\n output[child.className] = deserializeArray(\n child,\n deserializers,\n blockDeserializers\n );\n }\n });\n return output;\n};\n\nexport const deserializeHTML = (\n html: string,\n deserializers: CustomDeserializers,\n blockDeserializers: Array<unknown>\n): Record<string, unknown> | unknown[] => {\n //parent node is always div with classname of field -- get its child\n let HTMLnode = new DOMParser().parseFromString(html, 'text/html').body\n .children[0];\n\n //catch embedded object as a field\n if (HTMLnode?.getAttribute('data-level') === 'field') {\n HTMLnode = HTMLnode.children[0];\n }\n\n if (!HTMLnode) {\n return {};\n }\n\n let output: Record<string, unknown> | unknown[];\n\n //prioritize custom deserialization\n const deserialize = deserializers.types?.[HTMLnode.className];\n if (deserialize) {\n output = deserialize(HTMLnode as HTMLElement);\n } else if (HTMLnode.getAttribute('data-type') === 'object') {\n output = deserializeObject(HTMLnode, deserializers, blockDeserializers);\n } else if (HTMLnode.getAttribute('data-type') === 'array') {\n output = deserializeArray(HTMLnode, deserializers, blockDeserializers);\n } else {\n output = {};\n //eslint-disable-next-line no-console\n console.debug(\n `Tried to deserialize block ${HTMLnode.outerHTML} but failed to identify it!`\n );\n }\n\n return output;\n};\n\nexport const deserializeDocument = <\n TDocument extends Record<string, unknown> = Record<string, unknown>,\n>(\n serializedDoc: string,\n deserializers: CustomDeserializers = customDeserializers,\n blockDeserializers: Array<unknown> = customBlockDeserializers\n): TDocument => {\n const metadata: Record<string, unknown> = {};\n const head = new DOMParser().parseFromString(serializedDoc, 'text/html').head;\n\n Array.from(head.children).forEach((metaTag) => {\n const validTags = ['_id', '_rev', '_type'];\n const metaName = metaTag.getAttribute('name');\n if (metaName && validTags.includes(metaName)) {\n metadata[metaName] = metaTag.getAttribute('content');\n }\n });\n\n const content = deserializeHTML(\n serializedDoc,\n deserializers,\n blockDeserializers\n ) as Record<string, unknown>;\n\n return {\n ...content,\n ...metadata,\n } as TDocument;\n};\n\nexport const BaseDocumentDeserializer: Deserializer = {\n deserializeDocument,\n deserializeHTML,\n};\n","// Adapted from https://github.com/sanity-io/sanity-naive-html-serializer\n\nimport { ObjectField, TypedObject } from 'sanity';\n\nconst META_FIELDS = ['_key', '_type', '_id'];\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/*\n * Helper. If field-level translation pattern used, only sends over\n * content from the base language. Works recursively, so if users\n * use this pattern several layers deep, base language fields will still be found.\n */\nexport const languageObjectFieldFilter = (\n obj: Record<string, unknown>,\n baseLang: string\n): Record<string, unknown> => {\n const filterToLangField = (childObj: Record<string, unknown>) => {\n const filteredObj: Record<string, unknown> = {};\n filteredObj[baseLang] = childObj[baseLang];\n META_FIELDS.forEach((field) => {\n if (childObj[field]) {\n filteredObj[field] = childObj[field];\n }\n });\n return filteredObj;\n };\n\n const findBaseLang = (\n childObj: Record<string, unknown>\n ): Record<string, unknown> => {\n const filteredObj: Record<string, unknown> = {};\n META_FIELDS.forEach((field) => {\n if (childObj[field]) {\n filteredObj[field] = childObj[field];\n }\n });\n\n for (const key in childObj) {\n if (childObj.hasOwnProperty(key)) {\n const value: unknown = childObj[key];\n //we've reached a base language field, add it to\n //what we want to send to translation\n if (isRecord(value) && Object.hasOwn(value, baseLang)) {\n filteredObj[key] = filterToLangField(value);\n }\n //we have an array that may have language fields in its objects\n else if (\n Array.isArray(value) &&\n value.length &&\n typeof value[0] === 'object'\n ) {\n //recursively find and filter for any objects that have the base language\n const validLangObjects = value.reduce<Record<string, unknown>[]>(\n (validArr, objInArray) => {\n if (!isRecord(objInArray)) {\n return validArr;\n }\n if (objInArray._type === 'block') {\n validArr.push(objInArray);\n } else if (Object.hasOwn(objInArray, baseLang)) {\n validArr.push(filterToLangField(objInArray));\n } else {\n const filtered = findBaseLang(objInArray);\n const nonMetaFields = Object.keys(filtered).filter(\n (objInArrayKey) => META_FIELDS.indexOf(objInArrayKey) === -1\n );\n if (nonMetaFields.length) {\n validArr.push(filtered);\n }\n }\n return validArr;\n },\n []\n );\n if (validLangObjects.length) {\n filteredObj[key] = validLangObjects;\n }\n }\n //we have an object nested in an object\n //recurse down the tree\n else if (isRecord(value)) {\n const nestedLangObj = findBaseLang(value);\n const nonMetaFields = Object.keys(nestedLangObj).filter(\n (nestedObjKey) => META_FIELDS.indexOf(nestedObjKey) === -1\n );\n if (nonMetaFields.length) {\n filteredObj[key] = nestedLangObj;\n }\n }\n }\n }\n return filteredObj;\n };\n\n //send top level object into recursive function\n return findBaseLang(obj);\n};\n\n/**\n * Schema `options` namespaces that can exclude a field from translation.\n * `gt.exclude` is gt-sanity's own; `documentInternationalization.exclude`\n * (@sanity/document-internationalization) and `aiAssist.exclude`\n * (@sanity/assist) are honored so studios don't have to maintain a second\n * exclusion pattern for GT.\n */\ntype FieldExclusionOptions = {\n gt?: { exclude?: boolean };\n documentInternationalization?: { exclude?: boolean };\n aiAssist?: { exclude?: boolean };\n};\n\nexport const isFieldExcludedByOptions = (options: unknown): boolean => {\n if (!isRecord(options)) return false;\n const exclusionOptions = options as FieldExclusionOptions;\n return (\n exclusionOptions.gt?.exclude === true ||\n exclusionOptions.documentInternationalization?.exclude === true ||\n exclusionOptions.aiAssist?.exclude === true\n );\n};\n\n/** Resolves a schema type name to its raw type definition, if registered. */\nexport type SchemaTypeResolver = (\n typeName: string\n) => { type?: unknown; options?: unknown } | undefined;\n\nconst getFieldTypeName = (field: ObjectField): string | undefined => {\n const fieldType = (\n field as ObjectField & { type?: string | { name?: string } }\n ).type;\n return typeof fieldType === 'string' ? fieldType : fieldType?.name;\n};\n\n/**\n * Exclusion options on a type definition apply to every value of that type,\n * including through chains of type aliases. Walks the named type and each\n * alias target until a definition is excluded or the chain ends.\n */\nexport const isTypeExcludedByOptions = (\n typeName: string | undefined,\n resolveType: SchemaTypeResolver | undefined\n): boolean => {\n if (!resolveType) return false;\n const seen = new Set<string>();\n let current = typeName;\n while (current && !seen.has(current)) {\n seen.add(current);\n const typeDef = resolveType(current);\n if (!typeDef) return false;\n if (isFieldExcludedByOptions(typeDef.options)) return true;\n current = typeof typeDef.type === 'string' ? typeDef.type : undefined;\n }\n return false;\n};\n\n/**\n * A schema field is excluded from translation by the legacy `localize: false`\n * field property, by one of the `options` namespaces on the field itself, or\n * by exclusion options on the type definition the field references.\n */\nexport const isFieldExcludedFromTranslation = (\n field: ObjectField,\n resolveType?: SchemaTypeResolver\n): boolean => {\n const fieldMetadata = field as ObjectField & {\n localize?: boolean;\n options?: unknown;\n };\n return (\n fieldMetadata.localize === false ||\n isFieldExcludedByOptions(fieldMetadata.options) ||\n isTypeExcludedByOptions(getFieldTypeName(field), resolveType)\n );\n};\n\n/*\n * Eliminates stop-types and non-localizable fields\n * for document-level translation.\n */\nexport const fieldFilter = (\n obj: Record<string, unknown>,\n objFields: ObjectField[],\n stopTypes: string[],\n resolveType?: SchemaTypeResolver\n): TypedObject => {\n const filteredObj: TypedObject = {\n _type: typeof obj._type === 'string' ? obj._type : '',\n };\n\n const fieldFilterFunc = (field: ObjectField): boolean => {\n const fieldType = getFieldTypeName(field);\n\n if (isFieldExcludedFromTranslation(field, resolveType)) {\n return false;\n } else if (fieldType === 'string' || fieldType === 'text') {\n return true;\n } else if (Array.isArray(obj[field.name])) {\n return true;\n } else if (fieldType && !stopTypes.includes(fieldType)) {\n return true;\n }\n return false;\n };\n\n const validFields = [\n ...META_FIELDS,\n ...objFields.filter(fieldFilterFunc).map((field) => field.name),\n ];\n validFields.forEach((field) => {\n if (obj[field]) {\n filteredObj[field] = obj[field];\n }\n });\n return filteredObj;\n};\n","// Adapted from https://github.com/sanity-io/sanity-naive-html-serializer\n\nimport {\n defaultStopTypes,\n customSerializers,\n} from '../BaseSerializationConfig';\nimport { ObjectField, SanityDocument, TypedObject, Schema } from 'sanity';\nimport { TranslationLevel } from '../types';\nimport {\n fieldFilter,\n isFieldExcludedFromTranslation,\n isTypeExcludedByOptions,\n languageObjectFieldFilter,\n} from './fieldFilters';\nimport {\n PortableTextHtmlComponents,\n PortableTextTypeComponent,\n toHTML,\n} from '@portabletext/to-html';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\n\nconst META_FIELDS = ['_key', '_type', '_id', '_weak'];\n\ntype SchemaTypeWithFields = {\n type?: unknown;\n fields?: ObjectField[];\n options?: unknown;\n};\n\n/**\n * A raw (uncompiled) schema field or array-member definition. Inline object\n * declarations carry their `fields` here, and array declarations carry their\n * member definitions in `of`.\n */\ntype RawFieldDef = {\n name?: string;\n type?: string;\n fields?: ObjectField[];\n of?: RawFieldDef[];\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nexport const BaseDocumentSerializer = (schemas: Schema) => {\n /*\n * Helper function that allows us to get metadata (like `localize: false`) from schema fields.\n */\n const getSchema = (name: string): SchemaTypeWithFields | undefined =>\n schemas?._original?.types.find((s) => s.name === name) as\n | SchemaTypeWithFields\n | undefined;\n\n /*\n * Resolve a type name to its declared fields, following chains of type\n * aliases (a type whose definition just references another named type).\n */\n const resolveSchemaFields = (\n typeName: string | undefined\n ): ObjectField[] | undefined => {\n const seen = new Set<string>();\n let current = typeName;\n while (current && !seen.has(current)) {\n seen.add(current);\n const typeDef = getSchema(current);\n if (!typeDef) return undefined;\n if (typeDef.fields) return typeDef.fields;\n current = typeof typeDef.type === 'string' ? typeDef.type : undefined;\n }\n return undefined;\n };\n\n const serializeObject = (\n obj: TypedObject,\n stopTypes: string[],\n serializers: Partial<PortableTextHtmlComponents>,\n // Declared fields from the enclosing field or array-member definition.\n // Used when the value itself resolves to no schema type β€” anonymous\n // inline objects carry no `_type`.\n declaredFields?: ObjectField[]\n ) => {\n if (stopTypes.includes(obj._type)) {\n return '';\n }\n\n // The exclusion options also apply to a type definition's own `options`\n // (\"this field or type\" in the native plugins' semantics), including\n // through chains of type aliases.\n if (isTypeExcludedByOptions(obj._type, getSchema)) {\n return '';\n }\n\n //if user has declared a custom serializer, use that\n //instead of this method\n const typeSerializers = isRecord(serializers.types)\n ? serializers.types\n : ({} as PortableTextHtmlComponents['types']);\n const hasSerializer = Object.keys(typeSerializers).includes(obj._type);\n if (hasSerializer) {\n return toHTML([obj], { components: serializers });\n }\n\n //we don't need to worry about PT types\n if (obj._type === 'span' || obj._type === 'block') {\n return toHTML(obj, { components: serializers });\n }\n\n //if schema is available, encode values in the order they're declared in the schema,\n //since this will likely be more intuitive for a translator.\n //fields the schema excludes from translation (localize: false or an\n //options exclusion) are dropped here so exclusion applies at any depth.\n let fieldNames = Object.keys(obj).filter((key) => key !== '_type');\n const resolvedFields = resolveSchemaFields(obj._type);\n if (resolvedFields) {\n fieldNames = resolvedFields\n .filter((field) => !isFieldExcludedFromTranslation(field, getSchema))\n .map((field) => field.name)\n .filter((schemaKey) => Object.keys(obj).includes(schemaKey));\n } else if (declaredFields) {\n //anonymous inline objects have no schema type of their own; keep every\n //runtime key (undeclared data still round-trips) but drop keys whose\n //inline declaration excludes them from translation\n const excludedNames = new Set(\n declaredFields\n .filter((field) => isFieldExcludedFromTranslation(field, getSchema))\n .map((field) => field.name)\n );\n fieldNames = fieldNames.filter((name) => !excludedNames.has(name));\n }\n const knownFields = resolvedFields ?? declaredFields;\n\n //account for anonymous inline objects\n if (typeof obj === 'object' && !obj._type) {\n obj._type = '';\n }\n\n //in some cases, we might recurse through many objects of the same type\n //we should take all methods necessary to ensure state does not persist\n //otherwise we risk using old serialization methods on new items\n const newSerializationMethods: Record<string, PortableTextTypeComponent> =\n {};\n const tempType = `${obj._type}__temp_type__${Math.random().toString(36).substring(7)}`;\n const objToSerialize: TypedObject = { _type: tempType };\n //for our default serialization method, we only need to\n //capture metadata. the rest will be recursively turned into strings.\n META_FIELDS.filter((f) => f !== '_type').forEach((field) => {\n objToSerialize[field] = obj[field];\n });\n\n let innerHTML = '';\n\n //if it's a custom object, iterate through its keys to find and serialize translatable content\n fieldNames.forEach((fieldName) => {\n let htmlField = '';\n\n if (!META_FIELDS.includes(fieldName)) {\n const value = obj[fieldName];\n const fieldDef = knownFields?.find(\n (field) => field.name === fieldName\n ) as RawFieldDef | undefined;\n //strings are either string fields or have recursively been turned\n //into HTML because they were a nested object or array\n if (typeof value === 'string') {\n const htmlRegex = new RegExp(/<(\"[^\"]*\"|'[^']*'|[^'\">])*>/);\n if (htmlRegex.test(value)) {\n htmlField = value;\n } else {\n htmlField = `<span class=\"${fieldName}\">${value}</span>`;\n }\n }\n\n //array fields get filtered and its children serialized\n else if (Array.isArray(value)) {\n htmlField = serializeArray(\n value,\n fieldName,\n stopTypes,\n {\n ...serializers,\n types: { ...typeSerializers },\n },\n fieldDef?.of\n );\n }\n\n //this is an object in an object, serialize it first\n else if (isRecord(value)) {\n const embeddedObject = value as TypedObject;\n const embeddedFields = resolveSchemaFields(embeddedObject._type);\n let toTranslate = embeddedObject;\n if (embeddedFields) {\n toTranslate = fieldFilter(\n toTranslate,\n embeddedFields,\n stopTypes,\n getSchema\n );\n }\n const objHTML = serializeObject(\n toTranslate,\n stopTypes,\n {\n ...serializers,\n types: { ...typeSerializers },\n },\n fieldDef?.fields\n );\n htmlField = `<div class=\"${fieldName}\" data-level=\"field\">${objHTML}</div>`;\n }\n\n innerHTML += htmlField;\n }\n });\n\n if (!innerHTML) {\n return '';\n }\n\n newSerializationMethods[tempType] = ({ value }: { value: TypedObject }) => {\n let div = `<div class=\"${value._type.split('__temp_type__')[0]}\"`;\n if (value._key || value._id) {\n div += `id=\"${value._key ?? value._id}\"`;\n }\n\n return [div, ` data-type=\"object\">${innerHTML}</div>`].join('');\n };\n\n let serializedBlock = '';\n try {\n serializedBlock = toHTML(objToSerialize, {\n components: {\n ...serializers,\n types: {\n ...typeSerializers,\n ...newSerializationMethods,\n },\n },\n });\n } catch (err) {\n //eslint-disable-next-line no-console -- this is a warning\n console.warn(\n `Had issues serializing block of type \"${obj._type}\". Specify a serialization method for this block in your serialization config. Received error: ${err}`\n );\n }\n\n return serializedBlock;\n };\n\n const serializeArray = (\n fieldContent: Array<Record<string, unknown> | string>,\n fieldName: string,\n stopTypes: string[],\n serializers: Partial<PortableTextHtmlComponents>,\n // Declared member definitions (the array field's `of`), used to resolve\n // fields of anonymous inline object members that carry no schema type.\n memberDefs?: RawFieldDef[]\n ) => {\n //filter for any blocks that user has indicated\n //should not be sent for translation\n const validBlocks = fieldContent.filter(\n (block) =>\n typeof block === 'string' ||\n typeof block._type !== 'string' ||\n !stopTypes.includes(block._type)\n );\n\n //fields declared inline on the matching array-member definition\n const declaredMemberFields = (\n blockType: string | undefined\n ): ObjectField[] | undefined => {\n if (!memberDefs?.length) return undefined;\n const byName = memberDefs.find(\n (def) => def.name === blockType || def.type === blockType\n );\n if (byName?.fields) return byName.fields;\n if (!blockType && memberDefs.length === 1) return memberDefs[0].fields;\n return undefined;\n };\n\n const output = validBlocks.map((block) => {\n //if object in array is just a string, just return it\n if (typeof block === 'string') {\n return `<span>${block}</span>`;\n }\n //take out any fields in this block that should\n //not be sent to translation\n const blockType =\n typeof block._type === 'string' ? block._type : undefined;\n const memberFields = resolveSchemaFields(blockType);\n const filtered = memberFields\n ? fieldFilter(block, memberFields, stopTypes, getSchema)\n : block;\n //send to serialization method\n return serializeObject(\n filtered as TypedObject,\n stopTypes,\n serializers,\n declaredMemberFields(blockType)\n );\n });\n\n //encode this with data-level field\n return `<div class=\"${fieldName}\" data-type=\"array\">${output.join('')}</div>`;\n };\n\n /*\n * Main parent function: finds fields to translate, and feeds them to appropriate child serialization\n * methods.\n */\n const serializeDocument = (\n doc: SanityDocument,\n translationLevel: TranslationLevel = 'document',\n baseLang: string = libraryDefaultLocale,\n stopTypes = defaultStopTypes,\n serializers = customSerializers\n ) => {\n const schema = getSchema(doc._type);\n let filteredObj: Record<string, unknown> = {};\n\n //field level translations explicitly send over any fields that\n //match the base language, regardless of depth\n if (translationLevel === 'field') {\n filteredObj = languageObjectFieldFilter(doc, baseLang);\n }\n //otherwise, we can refer to the schema and a list of stop types\n //to determine what should not be sent\n else {\n filteredObj = fieldFilter(\n doc,\n schema?.fields ?? [],\n stopTypes,\n getSchema\n );\n }\n\n const serializedFields: Record<string, unknown> = {};\n\n for (const key in filteredObj) {\n if (filteredObj.hasOwnProperty(key) === false) continue;\n const value = filteredObj[key];\n const fieldDef = schema?.fields?.find((field) => field.name === key) as\n | RawFieldDef\n | undefined;\n\n if (typeof value === 'string') {\n serializedFields[key] = value;\n } else if (Array.isArray(value)) {\n serializedFields[key] = serializeArray(\n value.filter(\n (item): item is Record<string, unknown> | string =>\n typeof item === 'string' || isRecord(item)\n ),\n key,\n stopTypes,\n serializers,\n fieldDef?.of\n );\n } else if (\n value &&\n isRecord(value) &&\n !stopTypes.find((stopType) => stopType == value?._type)\n ) {\n const serialized = serializeObject(\n value as TypedObject,\n stopTypes,\n serializers,\n fieldDef?.fields\n );\n serializedFields[key] =\n `<div class=\"${key}\" data-level='field'>${serialized}</div>`;\n }\n }\n\n //create a valid HTML file\n const rawHTMLBody = document.createElement('body');\n rawHTMLBody.innerHTML = serializeObject(\n serializedFields as TypedObject,\n stopTypes,\n serializers\n );\n\n const rawHTMLHead = document.createElement('head');\n const metaFields = ['_id', '_type', '_rev'];\n //save our metadata as meta tags so we can use them later on\n metaFields.forEach((field) => {\n const metaEl = document.createElement('meta');\n metaEl.setAttribute('name', field);\n metaEl.setAttribute('content', doc[field] as string);\n rawHTMLHead.appendChild(metaEl);\n });\n //encode version so we can use the correct deserialization methods\n const versionMeta = document.createElement('meta');\n versionMeta.setAttribute('name', 'version');\n versionMeta.setAttribute('content', '3');\n rawHTMLHead.appendChild(versionMeta);\n\n const rawHTML = document.createElement('html');\n rawHTML.appendChild(rawHTMLHead);\n rawHTML.appendChild(rawHTMLBody);\n\n return {\n name: doc._id,\n content: rawHTML.outerHTML,\n };\n };\n\n return {\n serializeDocument,\n fieldFilter,\n languageObjectFieldFilter,\n serializeArray,\n serializeObject,\n };\n};\n","import {\n findLocaleItem,\n isInternationalizedArrayField,\n isRecord,\n} from './detect';\n\n/**\n * Collapse every internationalized-array field in a value down to just its\n * source-locale `value`, recursing into nested objects/arrays.\n *\n * This runs *before* the generic HTML serializer so that the per-locale item\n * arrays never reach `serializeArray` (which would otherwise emit every\n * locale). After collapsing, an `internationalizedArrayString` field is a plain\n * string, an `internationalizedArrayText` is a plain string, Portable Text is a\n * plain `block` array, and a custom value object is a plain object β€” all shapes\n * the existing document-level serializer already round-trips.\n *\n * Returns `undefined` when a field has no source-locale entry, so the caller\n * drops it (nothing to translate) rather than emitting an empty field.\n */\nexport function collapseToSourceLocale(\n value: unknown,\n sourceLocale: string\n): unknown {\n if (isInternationalizedArrayField(value)) {\n const sourceItem = findLocaleItem(value, sourceLocale);\n if (!sourceItem) {\n return undefined;\n }\n // Recurse: the source value may itself contain nested localized fields.\n return collapseToSourceLocale(sourceItem.value, sourceLocale);\n }\n\n if (Array.isArray(value)) {\n return value\n .map((item) => collapseToSourceLocale(item, sourceLocale))\n .filter((item) => item !== undefined);\n }\n\n if (isRecord(value)) {\n const collapsed: Record<string, unknown> = {};\n for (const key of Object.keys(value)) {\n const collapsedValue = collapseToSourceLocale(value[key], sourceLocale);\n if (collapsedValue !== undefined) {\n collapsed[key] = collapsedValue;\n }\n }\n return collapsed;\n }\n\n return value;\n}\n","import { SanityDocument, Schema } from 'sanity';\nimport { BaseDocumentDeserializer } from '../serialization/deserialize/BaseDocumentDeserializer';\nimport { BaseDocumentSerializer } from '../serialization/serialize/index';\nimport {\n defaultStopTypes,\n customSerializers,\n customBlockDeserializers,\n} from '../serialization/BaseSerializationConfig';\nimport { PortableTextHtmlComponents } from '@portabletext/to-html';\nimport { pluginConfig } from '../adapter/core';\nimport merge from 'lodash.merge';\nimport { deleteMatchingFields } from './applyDocuments';\nimport type { FieldMatcher } from '../adapter/types';\nimport { getPublishedId } from './documentIds';\nimport type {\n CustomDeserializers,\n TranslationLevel,\n} from '../serialization/types';\nimport { collapseToSourceLocale } from '../serialization/internationalizedArray/collapse';\n\nexport function deserializeDocument(document: string) {\n const deserializers = merge(\n { types: {} },\n pluginConfig.getAdditionalDeserializers()\n ) as CustomDeserializers;\n const blockDeserializers = [\n ...customBlockDeserializers,\n ...pluginConfig.getAdditionalBlockDeserializers(),\n ];\n const deserialized = BaseDocumentDeserializer.deserializeDocument(\n document,\n deserializers,\n blockDeserializers\n ) as SanityDocument;\n return deserialized;\n}\n\nexport function serializeDocument(\n document: SanityDocument,\n schema: Schema,\n baseLanguage: string,\n level: TranslationLevel = 'document'\n) {\n const stopTypes = [\n ...defaultStopTypes,\n ...pluginConfig.getAdditionalStopTypes(),\n ];\n const serializers = merge(\n customSerializers,\n pluginConfig.getAdditionalSerializers()\n ) satisfies Partial<PortableTextHtmlComponents>;\n\n let docToSerialize = stripIgnoredFields(\n document,\n pluginConfig.getIgnoreFields(),\n pluginConfig.getDedupeFields()\n );\n\n // The internationalized-array model collapses each localized field down to\n // its source-locale value, then serializes through the standard document\n // path so the existing HTML format and deserializer are reused as-is.\n let innerLevel: TranslationLevel = level;\n if (level === 'internationalizedArray') {\n docToSerialize = collapseToSourceLocale(\n docToSerialize,\n baseLanguage\n ) as SanityDocument;\n innerLevel = 'document';\n }\n\n const serialized = BaseDocumentSerializer(schema).serializeDocument(\n docToSerialize,\n innerLevel,\n baseLanguage,\n stopTypes,\n serializers\n );\n return serialized;\n}\n\nfunction stripIgnoredFields(\n document: SanityDocument,\n ignoreFields: FieldMatcher[],\n dedupeFields: FieldMatcher[]\n): SanityDocument {\n const fieldsToStrip = [...ignoreFields, ...dedupeFields];\n if (fieldsToStrip.length === 0) return document;\n\n const strippedDoc = JSON.parse(JSON.stringify(document)) as SanityDocument;\n\n deleteMatchingFields(\n getPublishedId(document._id),\n strippedDoc,\n fieldsToStrip\n );\n\n return strippedDoc;\n}\n","import { SanityClient, SanityDocument, Schema } from 'sanity';\nimport { pluginConfig } from '../adapter/core';\nimport { documentLevelPatch } from '../configuration/baseDocumentLevelConfig/documentLevelPatch';\nimport { internationalizedArrayPatch } from '../configuration/internationalizedArrayConfig/internationalizedArrayPatch';\nimport type {\n SerializedDocument,\n TranslationLevel,\n} from '../serialization/types';\nimport type { GTFile } from '../types';\nimport { serializeDocument } from '../utils/serialize';\n\n/**\n * A translation strategy bundles the serialize/patch pair for a given level.\n * The shared GT upload/enqueue/status/download workflow is identical across\n * strategies; only how a document is turned into the GT HTML file and how the\n * translated file is written back to Sanity differs.\n */\nexport type SanityTranslationAdapter = {\n level: TranslationLevel;\n serialize: (\n document: SanityDocument,\n schema: Schema,\n baseLanguage: string\n ) => SerializedDocument;\n patch: (\n docInfo: GTFile,\n deserialized: SanityDocument,\n localeId: string,\n client: SanityClient,\n mergeWithTargetLocale?: boolean\n ) => Promise<void>;\n};\n\nconst documentAdapter: SanityTranslationAdapter = {\n level: 'document',\n serialize: (document, schema, baseLanguage) =>\n serializeDocument(document, schema, baseLanguage, 'document'),\n patch: (docInfo, deserialized, localeId, client, mergeWithTargetLocale) =>\n documentLevelPatch(\n docInfo,\n deserialized,\n localeId,\n client,\n pluginConfig.getLanguageField(),\n mergeWithTargetLocale\n ),\n};\n\nconst internationalizedArrayAdapter: SanityTranslationAdapter = {\n level: 'internationalizedArray',\n serialize: (document, schema, baseLanguage) =>\n serializeDocument(document, schema, baseLanguage, 'internationalizedArray'),\n patch: (docInfo, deserialized, localeId, client) =>\n internationalizedArrayPatch(docInfo, deserialized, localeId, client),\n};\n\nfunction matchesFieldLevel(type: string | undefined): boolean {\n if (!type) {\n return false;\n }\n return pluginConfig\n .getFieldLevelDocuments()\n .some((filter) => filter.type === type);\n}\n\n/**\n * Resolve which strategy a document type uses:\n * - `document` β†’ always document-level (default; unchanged).\n * - `internationalizedArray` β†’ always the array strategy.\n * - `mixed` β†’ array strategy for `fieldLevelDocuments`, else\n * document-level.\n */\nexport function getTranslationStrategyForType(\n type: string | undefined\n): SanityTranslationAdapter {\n const level = pluginConfig.getTranslationLevel();\n if (level === 'internationalizedArray') {\n return internationalizedArrayAdapter;\n }\n if (level === 'mixed') {\n return matchesFieldLevel(type)\n ? internationalizedArrayAdapter\n : documentAdapter;\n }\n return documentAdapter;\n}\n\nexport function getTranslationStrategy(\n document: SanityDocument\n): SanityTranslationAdapter {\n return getTranslationStrategyForType(document._type);\n}\n","import type { GTFile, Secrets } from '../types';\nimport { api, gt, overrideConfig } from '../adapter/core';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport type { SerializedDocument } from '../serialization/types';\n\n// note: this function is used to create a new translation task\n// uploads files & calls the getTranslationTask function\nexport async function uploadFiles(\n documents: {\n info: GTFile;\n serializedDocument: SerializedDocument;\n }[],\n secrets: Secrets | null\n): Promise<Awaited<ReturnType<typeof api.uploadSourceFiles>>> {\n overrideConfig(secrets);\n const uploadResult = await api.uploadSourceFiles(\n documents.map(({ info, serializedDocument }) => ({\n source: {\n content: serializedDocument.content,\n fileName: `sanity/${info.documentId}`,\n fileId: info.documentId,\n fileFormat: 'HTML',\n locale: gt.sourceLocale || libraryDefaultLocale,\n versionId: info.versionId || undefined,\n },\n })),\n {\n sourceLocale: gt.sourceLocale || libraryDefaultLocale,\n }\n );\n return uploadResult;\n}\n","import { api, overrideConfig, pluginConfig } from '../adapter/core';\nimport type { Secrets } from '../types';\n\nexport async function initProject(\n uploadResult: Awaited<ReturnType<typeof api.uploadSourceFiles>>,\n options: { timeout?: number },\n secrets: Secrets\n): Promise<boolean> {\n overrideConfig(secrets);\n // Calculate timeout once for setup fetching\n // Accept number or numeric string, default to 600s\n const timeoutVal =\n options?.timeout !== undefined ? Number(options.timeout) : 600;\n const setupTimeoutSeconds = Number.isFinite(timeoutVal) ? timeoutVal : 600;\n\n const setupResult = await api.setupProject(uploadResult.uploadedFiles, {\n locales: pluginConfig.getLocales(),\n });\n\n if (setupResult.status === 'queued') {\n const { complete, jobs } = await api.awaitJobs([setupResult.setupJobId], {\n pollingIntervalSeconds: 2,\n timeoutSeconds: setupTimeoutSeconds,\n });\n const [job] = jobs;\n\n if (job?.status === 'completed') {\n // eslint-disable-next-line no-console\n console.log('Setup successfully completed');\n } else if (!complete) {\n // eslint-disable-next-line no-console\n console.log(\n 'Setup timed out β€” proceeding without setup (Timed out while waiting for setup generation)'\n );\n } else if (job?.status === 'failed') {\n // eslint-disable-next-line no-console\n console.log(\n `Setup failed β€” proceeding without setup (${job.error?.message ?? 'Unknown error'})`\n );\n } else {\n // eslint-disable-next-line no-console\n console.log('Setup status unknown β€” proceeding without setup');\n }\n }\n\n return true;\n}\n","import { libraryDefaultLocale } from 'generaltranslation/internal';\nimport { api, gt, overrideConfig } from '../adapter/core';\nimport type { Secrets } from '../types';\n\nexport async function createJobs(\n uploadResult: Awaited<ReturnType<typeof api.uploadSourceFiles>>,\n localeIds: string[],\n secrets: Secrets,\n // Discard any translation GT already holds for these files and retranslate\n // from source. Without this, GT reuses unchanged content β€” including\n // translations captured from the Studio β€” so a bad translation can never be\n // regenerated.\n force: boolean = false\n): Promise<Awaited<ReturnType<typeof api.enqueueFiles>>> {\n overrideConfig(secrets);\n const enqueueResult = await api.enqueueFiles(uploadResult.uploadedFiles, {\n sourceLocale: gt.sourceLocale || libraryDefaultLocale,\n targetLocales: localeIds,\n force,\n });\n return enqueueResult;\n}\n","import type { SanityClient, SanityDocument } from 'sanity';\nimport { pluginConfig } from '../adapter/core';\nimport { hasLocaleContent } from '../serialization/internationalizedArray/detect';\nimport type { TranslationFunctionContext } from '../types';\nimport {\n dedupeDocumentsPreferDraft,\n getDocumentPublishedId,\n} from '../utils/documentIds';\nimport {\n metadataTranslationRef,\n metadataTranslations,\n TRANSLATION_METADATA_TYPE,\n} from '../utils/translationMetadata';\nimport { serializeDocument } from '../utils/serialize';\nimport { getTranslationStrategy } from './strategy';\n\n/**\n * A translation that already exists in Sanity (a human-edited translated\n * document or a translated internationalized-array item), serialized to the\n * same HTML format the source document is uploaded in.\n */\nexport type ExistingTranslation = {\n locale: string;\n content: string;\n};\n\ntype TranslationMetadataRow = {\n sourceDocId?: string;\n translations?: { language?: string; docId?: string }[];\n};\n\n/**\n * Collect and serialize the translations that already exist in Sanity for the\n * given source documents, keyed by the source document's published id.\n *\n * - Document-level types: the translated documents linked through\n * `translation.metadata`, preferring drafts so unpublished human edits are\n * also preserved.\n * - Internationalized-array types: the target-locale items stored in the\n * source document itself, collapsed per locale.\n *\n * Locales without existing content are omitted, so callers only upload\n * translations that a human could actually have edited.\n */\nexport async function collectExistingTranslations(\n documents: SanityDocument[],\n targetLocaleIds: string[],\n { client, schema }: TranslationFunctionContext\n): Promise<Map<string, ExistingTranslation[]>> {\n const existing = new Map<string, ExistingTranslation[]>();\n if (documents.length === 0 || targetLocaleIds.length === 0) {\n return existing;\n }\n\n const sourceLocale = pluginConfig.getSourceLocale();\n const languageField = pluginConfig.getLanguageField();\n const localeIds = targetLocaleIds.filter(\n (localeId) => localeId !== sourceLocale\n );\n if (localeIds.length === 0) {\n return existing;\n }\n\n const documentLevelDocs: SanityDocument[] = [];\n for (const doc of documents) {\n const strategy = getTranslationStrategy(doc);\n if (strategy.level !== 'internationalizedArray') {\n documentLevelDocs.push(doc);\n continue;\n }\n\n // Array-level translations live in the source document itself. Collapsing\n // to the target locale reuses the source serialization path: fields with\n // no item for that locale are dropped, so only translated content ships.\n const { [languageField]: _language, ...cleanDoc } = doc;\n const translations: ExistingTranslation[] = [];\n for (const localeId of localeIds) {\n if (!hasLocaleContent(cleanDoc, localeId)) continue;\n const serialized = serializeDocument(\n cleanDoc as SanityDocument,\n schema,\n localeId,\n 'internationalizedArray'\n );\n translations.push({ locale: localeId, content: serialized.content });\n }\n if (translations.length > 0) {\n existing.set(getDocumentPublishedId(doc), translations);\n }\n }\n\n if (documentLevelDocs.length > 0) {\n const documentLevel = await collectDocumentLevelTranslations(\n documentLevelDocs,\n localeIds,\n sourceLocale,\n languageField,\n client,\n schema\n );\n for (const [sourceDocId, translations] of documentLevel) {\n existing.set(sourceDocId, translations);\n }\n }\n\n return existing;\n}\n\nasync function collectDocumentLevelTranslations(\n documents: SanityDocument[],\n localeIds: string[],\n sourceLocale: string,\n languageField: string,\n client: SanityClient,\n schema: TranslationFunctionContext['schema']\n): Promise<Map<string, ExistingTranslation[]>> {\n const existing = new Map<string, ExistingTranslation[]>();\n const sourceDocIds = documents.map(getDocumentPublishedId);\n\n const query = `*[\n _type == '${TRANSLATION_METADATA_TYPE}' &&\n ${metadataTranslationRef('$sourceLocale')} in $sourceDocIds\n ] {\n 'sourceDocId': ${metadataTranslationRef('$sourceLocale')},\n 'translations': ${metadataTranslations('in $localeIds', 'defined(value._ref)')}{\n language,\n 'docId': value._ref\n }\n }`;\n\n const metadataRows = await client.fetch<TranslationMetadataRow[]>(query, {\n sourceLocale,\n sourceDocIds,\n localeIds,\n });\n\n // Use the last entry per locale defensively: older plugin versions could\n // create duplicate locale entries when bulk imports raced.\n const refsBySource = new Map<string, Map<string, string>>();\n for (const row of metadataRows) {\n if (!row.sourceDocId) continue;\n const localeRefs =\n refsBySource.get(row.sourceDocId) ?? new Map<string, string>();\n for (const translation of row.translations ?? []) {\n if (translation.language && translation.docId) {\n localeRefs.set(translation.language, translation.docId);\n }\n }\n refsBySource.set(row.sourceDocId, localeRefs);\n }\n\n const translatedDocIds = Array.from(\n new Set(\n Array.from(refsBySource.values()).flatMap((localeRefs) =>\n Array.from(localeRefs.values())\n )\n )\n );\n if (translatedDocIds.length === 0) {\n return existing;\n }\n\n // Fetch published and draft versions in one query, preferring drafts so\n // unpublished human edits are included.\n const translatedDocs = await client.fetch<SanityDocument[]>(\n `*[_id in $ids || _id in $draftIds]`,\n {\n ids: translatedDocIds,\n draftIds: translatedDocIds.map((id) => `drafts.${id}`),\n }\n );\n const translatedById = new Map(\n dedupeDocumentsPreferDraft(translatedDocs).map((doc) => [\n getDocumentPublishedId(doc),\n doc,\n ])\n );\n\n for (const [sourceDocId, localeRefs] of refsBySource) {\n const translations: ExistingTranslation[] = [];\n for (const [localeId, translatedDocId] of localeRefs) {\n const translatedDoc = translatedById.get(translatedDocId);\n if (!translatedDoc) continue;\n const { [languageField]: _language, ...cleanDoc } = translatedDoc;\n const serialized = serializeDocument(\n cleanDoc as SanityDocument,\n schema,\n sourceLocale,\n 'document'\n );\n translations.push({ locale: localeId, content: serialized.content });\n }\n if (translations.length > 0) {\n existing.set(sourceDocId, translations);\n }\n }\n\n return existing;\n}\n","import type { SanityDocument } from 'sanity';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport { api, gt, overrideConfig } from '../adapter/core';\nimport { getDocumentPublishedId } from '../utils/documentIds';\nimport { collectExistingTranslations } from './collectExistingTranslations';\n\nimport type { Secrets, TranslationFunctionContext } from '../types';\n\nexport type CaptureExistingTranslationsInput = {\n documents: SanityDocument[];\n localeIds: string[];\n secrets: Secrets;\n context: TranslationFunctionContext;\n branchId?: string;\n};\n\nexport type CaptureExistingTranslationsResult = {\n /** Number of (document, locale) translations uploaded. */\n capturedCount: number;\n /** Number of documents that had at least one translation uploaded. */\n documentCount: number;\n};\n\nconst EMPTY_RESULT: CaptureExistingTranslationsResult = {\n capturedCount: 0,\n documentCount: 0,\n};\n\n/**\n * Upload the translations Sanity currently holds as the stored translation for\n * the source version General Translation already has, so a later translation of\n * a newer source version reuses them instead of regenerating.\n *\n * Must run before the current source revision is uploaded: the target version is\n * whatever General Translation holds now, which the upload would advance.\n * Documents with no source file there yet are skipped.\n */\nexport async function captureExistingTranslations({\n documents,\n localeIds,\n secrets,\n context,\n branchId,\n}: CaptureExistingTranslationsInput): Promise<CaptureExistingTranslationsResult> {\n if (documents.length === 0 || localeIds.length === 0) {\n return EMPTY_RESULT;\n }\n\n overrideConfig(secrets);\n const sourceLocale = gt.sourceLocale || libraryDefaultLocale;\n\n const seedFiles = await api.downloadFileBatch(\n documents.map((document) => ({\n fileId: getDocumentPublishedId(document),\n branchId,\n }))\n );\n const seedByFileId = new Map(\n (seedFiles.files ?? []).map((file) => [file.fileId, file])\n );\n\n const existing = await collectExistingTranslations(\n documents.filter((document) =>\n seedByFileId.has(getDocumentPublishedId(document))\n ),\n localeIds,\n context\n );\n\n const files = Array.from(existing.entries()).flatMap(\n ([documentId, translations]) => {\n const seed = seedByFileId.get(documentId);\n if (!seed || translations.length === 0) {\n return [];\n }\n const fileName = seed.fileName ?? `sanity/${documentId}`;\n const reference = {\n fileName,\n fileFormat: 'HTML' as const,\n fileId: seed.fileId,\n versionId: seed.versionId,\n branchId: seed.branchId,\n };\n\n return [\n {\n source: { ...reference, content: seed.data, locale: sourceLocale },\n translations: translations.map(({ locale, content }) => ({\n ...reference,\n content,\n locale,\n })),\n },\n ];\n }\n );\n\n if (files.length === 0) {\n return EMPTY_RESULT;\n }\n\n await api.uploadTranslations(files, { sourceLocale });\n\n return {\n capturedCount: files.reduce(\n (total, file) => total + file.translations.length,\n 0\n ),\n documentCount: files.length,\n };\n}\n","import type { GTFile, Secrets } from '../types';\nimport { api, gt, overrideConfig } from '../adapter/core';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport type { SerializedDocument } from '../serialization/types';\nimport type { ExistingTranslation } from './collectExistingTranslations';\n\n/**\n * Upload translations that already exist in Sanity for previously serialized\n * source documents. The endpoint is an upsert, so the Sanity content becomes\n * the stored translation for the source's fileId/versionId β€” this is how\n * human edits are preserved before (re-)enqueueing machine translation.\n *\n * Mirrors the CLI's upload workflow: each translation reuses the source\n * document's fileId and versionId and differs only by locale.\n */\nexport async function uploadTranslations(\n documents: {\n info: GTFile;\n serializedDocument: SerializedDocument;\n translations: ExistingTranslation[];\n }[],\n secrets: Secrets | null\n): Promise<Awaited<ReturnType<typeof api.uploadTranslations>> | null> {\n const withTranslations = documents.filter(\n (document) => document.translations.length > 0\n );\n if (withTranslations.length === 0) {\n return null;\n }\n\n overrideConfig(secrets);\n const sourceLocale = gt.sourceLocale || libraryDefaultLocale;\n return await api.uploadTranslations(\n withTranslations.map(({ info, serializedDocument, translations }) => ({\n source: {\n content: serializedDocument.content,\n fileName: `sanity/${info.documentId}`,\n fileId: info.documentId,\n fileFormat: 'HTML' as const,\n locale: sourceLocale,\n versionId: info.versionId || undefined,\n },\n translations: translations.map(({ locale, content }) => ({\n content,\n fileName: `sanity/${info.documentId}`,\n fileId: info.documentId,\n fileFormat: 'HTML' as const,\n locale,\n versionId: info.versionId || undefined,\n })),\n })),\n { sourceLocale }\n );\n}\n","import { api, overrideConfig } from '../adapter/core';\nimport { FileProperties } from '../adapter/types';\nimport { DownloadedFile } from 'generaltranslation/types';\nimport type { Secrets } from '../types';\n\n/**\n * Downloads multiple translation files in a single batch request\n * @param files - Array of files to download with their output paths\n * @param maxRetries - Maximum number of retry attempts\n * @param retryDelay - Delay between retries in milliseconds\n * @returns Object containing successful and failed file IDs\n */\nexport async function downloadTranslations(\n files: FileProperties[],\n secrets: Secrets,\n maxRetries = 3,\n retryDelay = 1000\n): Promise<DownloadedFile[]> {\n overrideConfig(secrets);\n let retries = 0;\n\n while (retries <= maxRetries) {\n try {\n // Download the files\n const responseData = await api.downloadFileBatch(\n files.map((file) => ({\n fileId: file.fileId,\n branchId: file.branchId,\n versionId: file.versionId,\n locale: file.locale,\n }))\n );\n const downloadedFiles = responseData.files || [];\n return downloadedFiles;\n } catch {\n // Increment retry counter and wait before next attempt\n retries++;\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\n }\n }\n\n return [];\n}\n","import type { Secrets } from '../types';\nimport { api, overrideConfig } from '../adapter/core';\nimport { FileProperties } from '../adapter/types';\nimport {\n createStableTranslationKey,\n createTranslationStatusKey,\n} from '../utils/documentIds';\n\nexport async function checkTranslationStatus(\n fileQueryData: FileProperties[],\n downloadStatus: {\n downloaded: Set<string>;\n failed: Set<string>;\n skipped: Set<string>;\n },\n secrets: Secrets\n) {\n overrideConfig(secrets);\n try {\n // Only query for files that haven't been downloaded yet\n const currentQueryData = fileQueryData.filter((item) => {\n const statusKey = createTranslationStatusKey(\n item.branchId,\n item.fileId,\n item.versionId,\n item.locale\n );\n const stableKey = createStableTranslationKey(\n item.branchId,\n item.fileId,\n item.locale\n );\n return (\n !downloadStatus.downloaded.has(statusKey) &&\n !downloadStatus.downloaded.has(stableKey) &&\n !downloadStatus.failed.has(statusKey) &&\n !downloadStatus.failed.has(stableKey) &&\n !downloadStatus.skipped.has(statusKey) &&\n !downloadStatus.skipped.has(stableKey)\n );\n });\n\n // If all files have been downloaded, we're done\n if (currentQueryData.length === 0) {\n return true;\n }\n // Check for translations\n const responseData = await api.queryFileData({\n translatedFiles: currentQueryData,\n });\n\n const translations = responseData.translatedFiles || [];\n\n // Filter for ready translations\n const readyTranslations = translations.filter(\n (translation) => translation.completedAt\n );\n\n return readyTranslations;\n } catch (error) {\n console.error('Error checking translation status', error);\n return [];\n }\n}\n","import type { GTFile, TranslationFunctionContext } from '../types';\nimport { deserializeDocument } from '../utils/serialize';\nimport { getTranslationStrategyForType } from './strategy';\n\nexport async function importDocument(\n docInfo: GTFile,\n localeId: string,\n document: string,\n context: TranslationFunctionContext,\n mergeWithTargetLocale: boolean = false\n) {\n const { client } = context;\n const deserialized = deserializeDocument(document);\n // The serialized HTML carries the document `_type` as a <meta> tag, so the\n // deserialized doc tells us which strategy to import with. versionId is not\n // used for the patch since the _rev travels inside the deserialized HTML.\n const strategy = getTranslationStrategyForType(\n deserialized._type as string | undefined\n );\n return strategy.patch(\n docInfo,\n deserialized,\n localeId,\n client,\n mergeWithTargetLocale\n );\n}\n","import { SanityClient, SanityDocument } from 'sanity';\nimport { pluginConfig } from '../adapter/core';\nimport { getPublishedId } from '../utils/documentIds';\nimport {\n metadataTranslationRef,\n metadataTranslations,\n TRANSLATION_METADATA_TYPE,\n} from '../utils/translationMetadata';\n\ninterface Reference {\n _type: 'reference';\n _ref: string;\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst isReference = (value: unknown): value is Reference =>\n isRecord(value) &&\n value._type === 'reference' &&\n typeof value._ref === 'string';\n\n/**\n * Function that:\n * 1. Finds all references in the document\n * 2. Fetches the referenced documents, looks for the translation.metadata file for each reference\n * 3. Updates the document reference with the other translated document reference\n * 4. Returns the document with the updated references\n */\nexport async function resolveRefs(\n doc: SanityDocument,\n locale: string,\n client: SanityClient\n) {\n const references = findReferences(doc);\n\n if (references.length === 0) {\n return doc;\n }\n\n const translatedRefs = await resolveTranslatedReferences(\n references,\n locale,\n client\n );\n return updateDocumentReferences(doc, translatedRefs);\n}\n\n/**\n * Write resolved references back without publishing them.\n *\n * `findLatestDraft` falls back to the published document when no draft exists,\n * which is the normal state for a translation that has already been published.\n * Patching that id would put the rewritten references live with no review step,\n * so seed a draft from the published state and patch that instead β€” the same\n * approach `internationalizedArrayPatch` takes.\n *\n * System fields are dropped from the patch: only the resolved content should be\n * written, and `_id` / `_rev` are the document's identity, not its content.\n */\nexport async function commitResolvedRefs(\n translatedDoc: SanityDocument,\n resolvedDoc: SanityDocument,\n client: SanityClient\n): Promise<void> {\n const {\n _id: _resolvedId,\n _rev: _resolvedRev,\n _createdAt: _resolvedCreatedAt,\n _updatedAt: _resolvedUpdatedAt,\n ...changes\n } = resolvedDoc;\n\n if (translatedDoc._id.startsWith('drafts.')) {\n await client.patch(translatedDoc._id).set(changes).commit();\n return;\n }\n\n const draftId = `drafts.${getPublishedId(translatedDoc._id)}`;\n await client\n .transaction()\n .createIfNotExists({ ...translatedDoc, _id: draftId })\n .patch(draftId, (patch) => patch.set(changes))\n .commit();\n}\n\n/**\n * Recursively finds all references in a document or object\n */\nfunction findReferences(\n obj: unknown,\n path: string[] = []\n): { ref: Reference; path: string[] }[] {\n if (!obj || typeof obj !== 'object') {\n return [];\n }\n\n const references: { ref: Reference; path: string[] }[] = [];\n\n if (isReference(obj)) {\n references.push({ ref: obj, path });\n }\n\n if (Array.isArray(obj)) {\n obj.forEach((item, index) => {\n references.push(...findReferences(item, [...path, index.toString()]));\n });\n } else if (isRecord(obj)) {\n Object.keys(obj).forEach((key) => {\n references.push(...findReferences(obj[key], [...path, key]));\n });\n }\n\n return references;\n}\n\n/**\n * Fetches translation metadata and resolves translated references\n */\nasync function resolveTranslatedReferences(\n references: { ref: Reference; path: string[] }[],\n locale: string,\n client: SanityClient\n): Promise<Map<string, string>> {\n const refIds = references.map((r) => r.ref._ref);\n const translatedRefs = new Map<string, string>();\n\n if (refIds.length === 0) {\n return translatedRefs;\n }\n\n const sourceLocale = pluginConfig.getSourceLocale();\n\n // Optimized GROQ query that directly returns only the needed translation pairs\n const query = `*[_type == \"${TRANSLATION_METADATA_TYPE}\" && count(${metadataTranslations('== $sourceLocale', 'value._ref in $refIds')}) > 0] {\n \"originalRef\": ${metadataTranslationRef('$sourceLocale')},\n \"translatedRefs\": ${metadataTranslations('== $locale')}.value._ref\n }[defined(originalRef) && count(translatedRefs) > 0]`;\n\n const translationPairs: { originalRef: string; translatedRefs: string[] }[] =\n await client.fetch(query, { refIds, sourceLocale, locale });\n\n // Build the translation map\n for (const { originalRef, translatedRefs: localeRefs } of translationPairs) {\n const translatedRef = localeRefs[localeRefs.length - 1];\n translatedRefs.set(originalRef, translatedRef);\n }\n\n return translatedRefs;\n}\n\n/**\n * Updates document references with their translated versions\n */\nfunction updateDocumentReferences(\n doc: SanityDocument,\n translatedRefs: Map<string, string>\n): SanityDocument {\n return updateReferencesRecursive(doc, translatedRefs) as SanityDocument;\n}\n\n/**\n * Recursively updates references in an object\n */\nfunction updateReferencesRecursive(\n obj: unknown,\n translatedRefs: Map<string, string>\n): unknown {\n if (!obj || typeof obj !== 'object') {\n return obj;\n }\n\n if (isReference(obj) && translatedRefs.has(obj._ref)) {\n return {\n ...obj,\n _ref: translatedRefs.get(obj._ref),\n };\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => updateReferencesRecursive(item, translatedRefs));\n }\n\n const updated: Record<string, unknown> = {};\n Object.keys(obj).forEach((key) => {\n updated[key] = updateReferencesRecursive(\n (obj as Record<string, unknown>)[key],\n translatedRefs\n );\n });\n\n return updated;\n}\n","import { SanityClient } from 'sanity';\nimport { pluginConfig } from '../adapter/core';\nimport { getPublishedId } from '../utils/documentIds';\nimport { findLatestDraft } from '../configuration/utils/findLatestDraft';\n\nexport async function findTranslatedDocuments(\n documentId: string,\n client: SanityClient\n) {\n const documents = await client.fetch(\n `*[_type == \"translation.metadata\" && references($documentId)]`\n );\n return documents;\n}\n\nexport async function findTranslatedDocumentForLocale(\n sourceDocumentId: string,\n localeId: string,\n client: SanityClient\n) {\n const cleanDocId = getPublishedId(sourceDocumentId);\n\n // Use the last locale entry defensively. Older versions could create\n // duplicate locale entries when bulk imports raced.\n const query = `*[\n _type == \"translation.metadata\" &&\n (\n translations[language == $sourceLocale][0].value._ref == $cleanDocId\n ) &&\n defined(translations[language == $localeId])\n ][0].translations[language == $localeId].value._ref`;\n\n const translatedDocIds = await client.fetch(query, {\n sourceLocale: pluginConfig.getSourceLocale(),\n cleanDocId,\n localeId,\n });\n\n const translatedDocId = translatedDocIds?.[translatedDocIds.length - 1];\n if (!translatedDocId) return null;\n\n return (await findLatestDraft(translatedDocId, client)) || null;\n}\n\nexport async function findDocument(documentId: string, client: SanityClient) {\n const query = `*[_id == $id]`;\n const params = { id: documentId };\n const document = await client.fetch(query, params);\n return document[0] || null;\n}\n","import { GTFile, TranslationFunctionContext } from '../types';\nimport { pluginConfig } from '../adapter/core';\nimport { importDocument } from '../translation/importDocument';\nimport { getPublishedId } from './documentIds';\n\nexport interface BatchProcessorOptions<T = unknown, R = unknown> {\n batchSize?: number;\n getConcurrencyKey?: (item: T) => string | undefined;\n onProgress?: (current: number, total: number) => void;\n onItemSuccess?: (item: T, result: R) => void;\n onItemFailure?: (item: T, error: unknown) => void;\n}\n\nexport interface ImportBatchItem {\n docInfo: GTFile;\n locale: string;\n data: string;\n translationContext: TranslationFunctionContext;\n key: string;\n}\n\nexport async function processBatch<T, R = unknown>(\n items: T[],\n processor: (item: T) => R | Promise<R>,\n options: BatchProcessorOptions<T, Awaited<R>> = {}\n): Promise<{\n successCount: number;\n failureCount: number;\n successfulItems: Awaited<R>[];\n failedItems: { item: T; error: unknown }[];\n}> {\n const {\n batchSize = 20,\n getConcurrencyKey,\n onProgress,\n onItemSuccess,\n onItemFailure,\n } = options;\n\n let successCount = 0;\n let failureCount = 0;\n const successfulItems: Awaited<R>[] = [];\n const failedItems: { item: T; error: unknown }[] = [];\n\n for (let i = 0; i < items.length; i += batchSize) {\n const batch = items.slice(i, i + batchSize);\n\n const pendingByKey = new Map<string, Promise<void>>();\n\n const batchPromises: Promise<\n | { success: true; item: T; result: Awaited<R> }\n | { success: false; item: T; error: unknown }\n >[] = batch.map(async (item) => {\n const concurrencyKey = getConcurrencyKey?.(item);\n const pending = concurrencyKey\n ? pendingByKey.get(concurrencyKey)\n : undefined;\n\n let release: () => void = () => {};\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n\n if (concurrencyKey) {\n pendingByKey.set(concurrencyKey, current);\n }\n\n try {\n if (pending) {\n await pending;\n }\n\n const result = await processor(item);\n onItemSuccess?.(item, result);\n return { success: true as const, item, result };\n } catch (error) {\n onItemFailure?.(item, error);\n return { success: false as const, item, error };\n } finally {\n release();\n if (concurrencyKey && pendingByKey.get(concurrencyKey) === current) {\n pendingByKey.delete(concurrencyKey);\n }\n }\n });\n\n const batchResults = await Promise.all(batchPromises);\n\n batchResults.forEach((result) => {\n if (result.success) {\n successCount++;\n successfulItems.push(result.result);\n } else {\n failureCount++;\n failedItems.push({ item: result.item, error: result.error });\n }\n });\n\n onProgress?.(i + batch.length, items.length);\n }\n\n return { successCount, failureCount, successfulItems, failedItems };\n}\n\nexport async function processImportBatch(\n items: ImportBatchItem[],\n options: BatchProcessorOptions<ImportBatchItem, string> = {}\n): Promise<{\n successCount: number;\n failureCount: number;\n successfulImports: string[];\n failedItems: { item: ImportBatchItem; error: unknown }[];\n}> {\n const successfulImports: string[] = [];\n\n const result = await processBatch(\n items,\n async (item: ImportBatchItem) => {\n await importDocument(\n item.docInfo,\n item.locale,\n item.data,\n item.translationContext,\n false\n );\n return item.key;\n },\n {\n ...options,\n // Serialize all locales of the same document when imports may patch the\n // source document in place: internationalized-array imports do a\n // read-merge-set, so concurrent locale imports would clobber each other\n // (last write wins). Document-level imports write to separate per-locale\n // documents and stay parallel. In 'mixed' mode the per-document strategy\n // is only known after deserialization, so serialize conservatively.\n getConcurrencyKey: (item: ImportBatchItem) =>\n pluginConfig.getTranslationLevel() === 'document'\n ? undefined\n : getPublishedId(item.docInfo.documentId),\n onItemSuccess: (item: ImportBatchItem, key: string) => {\n successfulImports.push(key);\n options.onItemSuccess?.(item, key);\n },\n onItemFailure: (item: ImportBatchItem, error: unknown) => {\n console.error(\n `Failed to import ${item.docInfo.documentId} (${item.locale}):`,\n error\n );\n options.onItemFailure?.(item, error);\n },\n }\n );\n\n return {\n ...result,\n successfulImports,\n };\n}\n","import { Secrets, TranslationFunctionContext } from '../types';\nimport { downloadTranslations } from '../translation/downloadTranslations';\nimport { processImportBatch, ImportBatchItem } from './batchProcessor';\nimport type { FileProperties, TranslationStatus } from '../adapter/types';\nimport { createStableTranslationKey, getPublishedId } from './documentIds';\n\nexport interface ImportResult {\n successCount: number;\n failureCount: number;\n successfulImports: string[];\n}\n\n/** A status that has passed the ready check, so its `fileData` is present. */\nexport type ReadyTranslationStatus = TranslationStatus & {\n fileData: FileProperties;\n};\n\nexport interface ImportOptions {\n filterReadyFiles?: (key: string, status: ReadyTranslationStatus) => boolean;\n onProgress?: (current: number, total: number) => void;\n /**\n * The translation-status keys selected for import, reported before any\n * downloading starts. These come straight from the status map, which is what\n * the locale rows are indexed by, so a caller can light up a row without\n * rederiving anything. `onImportSuccess` builds its key from the downloaded\n * file; the two agree today, and reporting the map keys here keeps that from\n * being load-bearing.\n */\n onSelectedKeys?: (statusKeys: string[]) => void;\n onImportSuccess?: (key: string) => void;\n}\n\nexport async function getReadyFilesForImport(\n translationStatuses: Map<string, TranslationStatus>,\n options: ImportOptions = {}\n): Promise<FileProperties[]> {\n const { filterReadyFiles = () => true } = options;\n const readyFilesByDocumentLocale = new Map<string, FileProperties>();\n const selectedStatusKeys: string[] = [];\n\n for (const [key, status] of translationStatuses.entries()) {\n const readyStatus =\n status.isReady && status.fileData\n ? ({ ...status, fileData: status.fileData } as ReadyTranslationStatus)\n : null;\n if (readyStatus && filterReadyFiles(key, readyStatus)) {\n selectedStatusKeys.push(key);\n const fileData = {\n fileId: getPublishedId(readyStatus.fileData.fileId),\n versionId: readyStatus.fileData.versionId,\n branchId: readyStatus.fileData.branchId,\n locale: readyStatus.fileData.locale,\n };\n readyFilesByDocumentLocale.set(\n createStableTranslationKey(\n fileData.branchId,\n fileData.fileId,\n fileData.locale\n ),\n fileData\n );\n }\n }\n\n options.onSelectedKeys?.(selectedStatusKeys);\n\n return Array.from(readyFilesByDocumentLocale.values());\n}\n\n/**\n * Identifies one file+locale across an import. Derived the same way for the\n * files queued up front and the files that come back from the download, so\n * `onImportStart` and `onImportSuccess` always agree on a key.\n */\nfunction importKeyFor(file: {\n branchId?: string;\n fileId?: string;\n versionId?: string;\n locale?: string | null;\n}): string {\n return `${file.branchId}:${file.fileId}:${file.versionId}:${file.locale}`;\n}\n\nexport async function importTranslations(\n readyFiles: FileProperties[],\n secrets: Secrets,\n translationContext: TranslationFunctionContext,\n options: ImportOptions = {}\n): Promise<ImportResult> {\n if (readyFiles.length === 0) {\n return { successCount: 0, failureCount: 0, successfulImports: [] };\n }\n\n const downloadedFiles = await downloadTranslations(readyFiles, secrets);\n\n const importItems: ImportBatchItem[] = downloadedFiles.map((file) => {\n const data =\n typeof file.data === 'string'\n ? file.data\n : JSON.stringify(file.data ?? '');\n return {\n docInfo: {\n documentId: file.fileId,\n versionId: file.versionId,\n },\n locale: file.locale!,\n data,\n translationContext,\n key: importKeyFor(file),\n };\n });\n\n const result = await processImportBatch(importItems, {\n onProgress: options.onProgress,\n onItemSuccess: (item, key) => {\n options.onImportSuccess?.(key);\n },\n });\n\n return {\n successCount: result.successCount,\n failureCount: result.failureCount,\n successfulImports: result.successfulImports,\n };\n}\n","import { SanityClient } from 'sanity';\nimport { processBatch } from '../utils/batchProcessor';\nimport { findDocument } from './findDocuments';\nimport { getPublishedId } from '../utils/documentIds';\n\n/**\n * Selects the translation documents belonging to a set of source documents.\n *\n * A document is classified as a source by its id, never by the `language`\n * label on its metadata entry. Locale codes get renamed β€” `en` to `en-US`, say\n * β€” and entries written beforehand keep the old code, so a group whose source\n * label no longer matches the configured source locale would be skipped\n * entirely and its source would be mistaken for a translation.\n *\n * The two id sets answer different questions:\n *\n * - `$publishedDocumentIds` β€” which groups are in scope. There is nothing to\n * publish until the source itself exists published.\n * - `$sourceDocumentIds` β€” what counts as a source. Every source under\n * management, including ones that only exist as a draft, so a source is\n * never returned as a translation of some other document.\n *\n * Known limitation: a group is in scope if it references any requested source,\n * so metadata that wrongly links two sources into one group can return the\n * other source's translations. Which source owns a translation is not\n * recoverable from the metadata once it is inconsistent, and the alternative β€”\n * skipping ambiguous groups β€” silently drops valid translations, which is the\n * worse outcome.\n */\nexport const TRANSLATION_DOCS_FOR_PUBLISH_QUERY = `*[\n _type == 'translation.metadata' &&\n count(translations[defined(value._ref) && value._ref in $publishedDocumentIds]) > 0\n] {\n 'translationDocs': translations[\n defined(value._ref) && !(value._ref in $sourceDocumentIds)\n ]{\n _key,\n 'docId': value._ref\n }\n}`;\n\nexport async function publishDocument(\n documentId: string,\n client: SanityClient\n) {\n try {\n // only publish if the document is a draft\n if (documentId.startsWith('drafts.')) {\n await client.action(\n {\n actionType: 'sanity.action.document.publish',\n draftId: documentId,\n publishedId: getPublishedId(documentId),\n },\n {}\n );\n }\n } catch (error) {\n console.error('Error publishing document', error);\n }\n}\n\nexport async function publishTranslations(\n documentIds: string[],\n client: SanityClient\n) {\n const publishedDocumentIds: string[] = [];\n await processBatch(\n documentIds,\n async (documentId) => {\n const document = await findDocument(`drafts.${documentId}`, client);\n if (!document) {\n return { documentId, published: false };\n }\n await publishDocument(document._id, client);\n publishedDocumentIds.push(documentId);\n return { documentId, published: true };\n },\n {\n onItemFailure: (documentId, error) => {\n console.error(`Failed to publish document ${documentId}:`, error);\n },\n }\n );\n return publishedDocumentIds;\n}\n","import type { Adapter, Secrets } from '../types';\nimport { gt, pluginConfig } from './core';\n\n// note: this function is used to get the available locales for a project\nexport const getLocales: Adapter['getLocales'] = async (\n _secrets: Secrets | null\n) => {\n return pluginConfig.getLocales().map((locale: string) => ({\n localeId: locale,\n description: gt.getLocaleProperties(locale).name,\n enabled: true,\n }));\n};\n","import type { TranslationPreferences } from '../adapter/types';\n\n/**\n * These are user preferences, not run state, so they persist across sessions\n * rather than resetting with the tab. Plugin config sets the starting point;\n * once the user touches a switch, their choice wins. Keyed by project + dataset\n * so Studios sharing an origin don't collide.\n */\nexport const getPreferencesStorageKey = (\n projectId: string | undefined,\n dataset: string | undefined\n) => `gt-sanity:preferences:${projectId ?? ''}:${dataset ?? ''}`;\n\nconst isPlainRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * Read the stored preferences, falling back to `defaults` for anything the\n * stored object doesn't specify.\n */\nexport function readPreferences(\n storageKey: string,\n defaults: TranslationPreferences\n): TranslationPreferences {\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (!raw) return defaults;\n const parsed: unknown = JSON.parse(raw);\n if (!isPlainRecord(parsed)) return defaults;\n // Merge per key: a preference added in a later release falls back to its\n // default instead of being dropped by a stale stored object.\n const merged = { ...defaults };\n const keys = Object.keys(defaults) as (keyof TranslationPreferences)[];\n for (const key of keys) {\n const value = parsed[key];\n if (typeof value === 'boolean') merged[key] = value;\n }\n return merged;\n } catch {\n return defaults;\n }\n}\n\nexport function writePreferences(\n storageKey: string,\n value: TranslationPreferences\n): void {\n try {\n window.localStorage.setItem(storageKey, JSON.stringify(value));\n } catch {\n // localStorage unavailable (SSR, private mode, quota) β€” the choice still\n // applies, it just won't survive a reload.\n }\n}\n","import React, {\n createContext,\n useContext,\n useState,\n useCallback,\n useEffect,\n useRef,\n ReactNode,\n} from 'react';\nimport { SanityDocument, useSchema } from 'sanity';\nimport { useToast } from '@sanity/ui/toast';\nimport { useClient } from '../hooks/useClient';\nimport { useSecrets } from '../hooks/useSecrets';\nimport {\n GTFile,\n Secrets,\n TranslationLocale,\n TranslationFunctionContext,\n} from '../types';\nimport { api, overrideConfig, pluginConfig } from '../adapter/core';\nimport { getTranslationStrategy } from '../translation/strategy';\nimport { uploadFiles } from '../translation/uploadFiles';\nimport { initProject } from '../translation/initProject';\nimport { createJobs } from '../translation/createJobs';\nimport { captureExistingTranslations } from '../translation/captureExistingTranslations';\nimport { collectExistingTranslations } from '../translation/collectExistingTranslations';\nimport { uploadTranslations } from '../translation/uploadTranslations';\nimport { downloadTranslations } from '../translation/downloadTranslations';\nimport { checkTranslationStatus } from '../translation/checkTranslationStatus';\nimport { importDocument } from '../translation/importDocument';\nimport { commitResolvedRefs, resolveRefs } from '../sanity-api/resolveRefs';\nimport { findTranslatedDocumentForLocale } from '../sanity-api/findDocuments';\nimport {\n getReadyFilesForImport,\n importTranslations,\n ImportOptions,\n} from '../utils/importUtils';\nimport { processBatch } from '../utils/batchProcessor';\nimport {\n publishTranslations,\n TRANSLATION_DOCS_FOR_PUBLISH_QUERY,\n} from '../sanity-api/publishDocuments';\nimport { getLocales } from '../adapter/getLocales';\nimport type {\n FileProperties,\n TranslationPreferences,\n TranslationStatus,\n} from '../adapter/types';\nimport {\n createStableTranslationKey,\n createTranslationStatusKey,\n dedupeDocumentsPreferDraft,\n getDocumentPublishedId,\n getPublishedId,\n} from '../utils/documentIds';\nimport {\n getPreferencesStorageKey,\n readPreferences,\n writePreferences,\n} from '../utils/translationPreferences';\n\ninterface ImportProgress {\n current: number;\n total: number;\n isImporting: boolean;\n}\n\ninterface DownloadStatus {\n downloaded: Set<string>;\n failed: Set<string>;\n skipped: Set<string>;\n}\n\ntype ExistingTranslationMetadata = {\n sourceDocId: string;\n existingTranslations?: string[];\n};\n\ntype TranslationDocumentMetadata = {\n translationDocs?: { docId?: string }[];\n};\n\nexport type TranslateAllOptions = {\n /**\n * Discard the translations GT already holds and retranslate from source.\n * Also skips capturing Studio-side edits β€” capturing them would immediately\n * be reused as the baseline, which is the opposite of what a retranslate is\n * asking for.\n */\n force?: boolean;\n};\n\ninterface TranslationsContextType {\n // State\n isBusy: boolean;\n documents: SanityDocument[];\n locales: TranslationLocale[];\n autoRefresh: boolean;\n autoImport: boolean;\n autoPatchReferences: boolean;\n autoPublish: boolean;\n preserveExistingTranslations: boolean;\n loadingDocuments: boolean;\n importProgress: ImportProgress;\n importedTranslations: Set<string>;\n existingTranslations: Set<string>;\n downloadStatus: DownloadStatus;\n translationStatuses: Map<string, TranslationStatus>;\n /**\n * Status keys enqueued this session and not yet reported ready. Non-empty\n * means General Translation is still working, which nothing else in the\n * status map distinguishes from \"never translated\" β€” both read as 0%.\n */\n pendingTranslations: Set<string>;\n /**\n * Status keys currently being written to Sanity. `importProgress` only counts\n * how many are done, so without this a locale row cannot tell \"queued in this\n * import\" from \"not part of it\" while a bulk import runs.\n */\n importingTranslations: Set<string>;\n isRefreshing: boolean;\n loadingSecrets: boolean;\n secrets: Secrets | null;\n branchId: string | undefined;\n // Version to use for translation status keys and GT file queries. Prefers\n // the _rev pinned at upload time over the live _rev, so in-place imports\n // (internationalized arrays) bumping the document _rev don't orphan the\n // statuses of the version actually uploaded to GT.\n getVersionId: (document: SanityDocument) => string;\n\n // Actions\n setLocales: (locales: TranslationLocale[]) => void;\n setAutoRefresh: (value: boolean) => void;\n setAutoImport: (value: boolean) => void;\n setAutoPatchReferences: (value: boolean) => void;\n setAutoPublish: (value: boolean) => void;\n setPreserveExistingTranslations: (value: boolean) => void;\n handleTranslateAll: (options?: TranslateAllOptions) => Promise<void>;\n handleUploadExistingTranslations: () => Promise<void>;\n handleImportAll: () => Promise<void>;\n handleImportMissing: () => Promise<void>;\n handleRefreshAll: (options?: { silent?: boolean }) => Promise<void>;\n handleImportDocument: (\n documentId: string,\n versionId: string,\n localeId: string\n ) => Promise<void>;\n handlePatchDocumentReferences: () => Promise<number>;\n handlePublishAllTranslations: () => Promise<number>;\n}\n\nconst TranslationsContext = createContext<TranslationsContextType | null>(null);\n\n// Pinned upload versions are mirrored to sessionStorage so they survive a\n// Studio page refresh: falling back to the live document._rev after a refresh\n// would query GT with a version that was never uploaded (in-place imports bump\n// the _rev), making completed translations show as \"not started\". Keyed by\n// project + dataset so Studios sharing an origin don't collide.\nconst getUploadedVersionsStorageKey = (\n projectId: string | undefined,\n dataset: string | undefined\n) => `gt-sanity:uploadedVersions:${projectId ?? ''}:${dataset ?? ''}`;\n\nfunction readUploadedVersions(storageKey: string): Map<string, string> {\n try {\n const raw = window.sessionStorage.getItem(storageKey);\n if (!raw) return new Map();\n const parsed: unknown = JSON.parse(raw);\n if (!isPlainRecord(parsed)) return new Map();\n return new Map(\n Object.entries(parsed).filter(\n (entry): entry is [string, string] => typeof entry[1] === 'string'\n )\n );\n } catch {\n return new Map();\n }\n}\n\nfunction writeUploadedVersions(\n storageKey: string,\n versions: Map<string, string>\n): void {\n try {\n window.sessionStorage.setItem(\n storageKey,\n JSON.stringify(Object.fromEntries(versions))\n );\n } catch {\n // sessionStorage unavailable (SSR, private mode, quota) β€” pinned versions\n // fall back to in-memory only.\n }\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport const useTranslations = () => {\n const context = useContext(TranslationsContext);\n if (!context) {\n throw new Error('useTranslations must be used within TranslationsProvider');\n }\n return context;\n};\n\ninterface TranslationsProviderProps {\n children: ReactNode;\n singleDocument?: SanityDocument | null;\n}\n\nexport const TranslationsProvider: React.FC<TranslationsProviderProps> = ({\n children,\n singleDocument,\n}) => {\n const [isBusy, setIsBusy] = useState(false);\n const [documents, setDocuments] = useState<SanityDocument[]>([]);\n const [locales, setLocales] = useState<TranslationLocale[]>([]);\n const [loadingDocuments, setLoadingDocuments] = useState(false);\n const [importProgress, setImportProgress] = useState<ImportProgress>({\n current: 0,\n total: 0,\n isImporting: false,\n });\n const [importedTranslations, setImportedTranslations] = useState<Set<string>>(\n new Set()\n );\n const [existingTranslations, setExistingTranslations] = useState<Set<string>>(\n new Set()\n );\n const [downloadStatus, setDownloadStatus] = useState<DownloadStatus>({\n downloaded: new Set<string>(),\n failed: new Set<string>(),\n skipped: new Set<string>(),\n });\n const downloadStatusRef = useRef(downloadStatus);\n const [translationStatuses, setTranslationStatuses] = useState<\n Map<string, TranslationStatus>\n >(new Map());\n const [pendingTranslations, setPendingTranslations] = useState<Set<string>>(\n new Set()\n );\n const [importingTranslations, setImportingTranslations] = useState<\n Set<string>\n >(new Set());\n const [isRefreshing, setIsRefreshing] = useState(false);\n\n const client = useClient();\n const { projectId, dataset } = client.config();\n const uploadedVersionsStorageKey = getUploadedVersionsStorageKey(\n projectId,\n dataset\n );\n const [uploadedVersions, setUploadedVersions] = useState<Map<string, string>>(\n () => readUploadedVersions(uploadedVersionsStorageKey)\n );\n const preferencesStorageKey = getPreferencesStorageKey(projectId, dataset);\n const [preferences, setPreferences] = useState<TranslationPreferences>(() =>\n readPreferences(preferencesStorageKey, pluginConfig.getPreferences())\n );\n const {\n autoRefresh,\n autoImport,\n autoPatchReferences,\n autoPublish,\n preserveExistingTranslations,\n } = preferences;\n\n // Persist from the event handler rather than an effect: these only ever\n // change in response to the user flipping a switch.\n const setPreference = useCallback(\n (key: keyof TranslationPreferences, value: boolean) => {\n const next = { ...preferences, [key]: value };\n setPreferences(next);\n writePreferences(preferencesStorageKey, next);\n },\n [preferences, preferencesStorageKey]\n );\n const setAutoRefresh = useCallback(\n (value: boolean) => setPreference('autoRefresh', value),\n [setPreference]\n );\n const setAutoImport = useCallback(\n (value: boolean) => setPreference('autoImport', value),\n [setPreference]\n );\n const setAutoPatchReferences = useCallback(\n (value: boolean) => setPreference('autoPatchReferences', value),\n [setPreference]\n );\n const setAutoPublish = useCallback(\n (value: boolean) => setPreference('autoPublish', value),\n [setPreference]\n );\n const setPreserveExistingTranslations = useCallback(\n (value: boolean) => setPreference('preserveExistingTranslations', value),\n [setPreference]\n );\n const schema = useSchema();\n const translationContext: TranslationFunctionContext = { client, schema };\n const toast = useToast();\n const { loading: loadingSecrets, secrets } = useSecrets<Secrets>(\n pluginConfig.getSecretsNamespace()\n );\n const [branchId, setBranchId] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n downloadStatusRef.current = downloadStatus;\n }, [downloadStatus]);\n\n const getVersionId = useCallback(\n (document: SanityDocument) =>\n uploadedVersions.get(getDocumentPublishedId(document)) ?? document._rev,\n [uploadedVersions]\n );\n\n const fetchDocuments = useCallback(async () => {\n setLoadingDocuments(true);\n try {\n if (singleDocument) {\n setDocuments([singleDocument]);\n return;\n }\n\n const translateDocuments = pluginConfig.getTranslateDocuments();\n\n const filterConditions = translateDocuments\n .map((filter) => {\n if (filter.type && filter.documentId) {\n return `(_type == \"${filter.type}\" && _id == \"${filter.documentId}\")`;\n } else if (filter.type) {\n return `_type == \"${filter.type}\"`;\n } else if (filter.documentId) {\n return `_id == \"${filter.documentId}\"`;\n }\n return null;\n })\n .filter(Boolean);\n\n const languageField = pluginConfig.getLanguageField();\n const sourceLocale = pluginConfig.getSourceLocale();\n const languageFilter = `(!defined(${languageField}) || ${languageField} == \"${sourceLocale}\")`;\n\n let query;\n if (filterConditions.length === 0) {\n query = `*[!(_type in [\"system.group\"]) && !(_id in path(\"_.**\")) && ${languageFilter}]`;\n } else {\n const filterQuery = filterConditions.join(' || ');\n query = `*[!(_type in [\"system.group\"]) && !(_id in path(\"_.**\")) && (${filterQuery}) && ${languageFilter}]`;\n }\n\n const docs = await client.fetch(query);\n setDocuments(dedupeDocumentsPreferDraft(docs));\n } catch {\n toast.push({\n title:\n 'Documents could not be loaded. Check your Sanity connection and try refreshing.',\n status: 'error',\n closable: true,\n });\n } finally {\n setLoadingDocuments(false);\n }\n }, [client, singleDocument]);\n\n const fetchLocales = useCallback(async () => {\n if (!secrets) return;\n try {\n const availableLocales = await getLocales(secrets);\n setLocales(availableLocales);\n } catch {\n toast.push({\n title:\n 'Locales could not be loaded. Check your General Translation credentials and try again.',\n status: 'error',\n closable: true,\n });\n }\n }, [secrets]);\n\n const fetchExistingTranslations = useCallback(async () => {\n if (!documents.length || !locales.length) return;\n\n try {\n const sourceLocale = pluginConfig.getSourceLocale();\n const availableLocaleIds = locales\n .filter((locale) => locale.enabled !== false)\n .map((locale) => locale.localeId);\n\n const documentIds = documents.map(getDocumentPublishedId);\n\n const query = `*[\n _type == 'translation.metadata' &&\n translations[language == $sourceLocale][0].value._ref in $documentIds\n ] {\n 'sourceDocId': translations[language == $sourceLocale][0].value._ref,\n 'existingTranslations': translations[language in $localeIds].language\n }`;\n\n const existingMetadata = await client.fetch<\n ExistingTranslationMetadata[]\n >(query, {\n sourceLocale,\n documentIds,\n localeIds: availableLocaleIds,\n });\n\n const existing = new Set<string>();\n existingMetadata.forEach((metadata) => {\n metadata.existingTranslations?.forEach((localeId: string) => {\n if (localeId !== sourceLocale) {\n existing.add(\n createStableTranslationKey(\n undefined,\n metadata.sourceDocId,\n localeId\n )\n );\n }\n });\n });\n\n setExistingTranslations(existing);\n } catch (error) {\n console.error('Error fetching existing translations:', error);\n toast.push({\n title:\n 'Existing translations could not be loaded. Try refreshing before importing.',\n status: 'error',\n closable: true,\n });\n }\n }, [documents, locales, client]);\n\n const serializeSourceDocuments = useCallback(\n () =>\n documents\n .map((doc) => {\n const { [pluginConfig.getLanguageField()]: _, ...cleanDoc } = doc;\n const baseLanguage = pluginConfig.getSourceLocale();\n try {\n const strategy = getTranslationStrategy(doc);\n return {\n info: {\n documentId: getDocumentPublishedId(doc),\n versionId: doc._rev,\n },\n serializedDocument: strategy.serialize(\n cleanDoc as typeof doc,\n schema,\n baseLanguage\n ),\n };\n } catch (error) {\n console.error('Error transforming document', doc._id, error);\n }\n return null;\n })\n .filter((doc) => doc !== null),\n [documents, schema]\n );\n\n const handleTranslateAll = useCallback(\n async ({ force = false }: TranslateAllOptions = {}) => {\n if (!secrets || documents.length === 0) return;\n\n setIsBusy(true);\n\n try {\n const availableLocaleIds = locales\n .filter((locale) => locale.enabled !== false)\n .map((locale) => locale.localeId);\n\n // Send any Studio-side edits to existing translations back to GT first,\n // pinned to the source version they belong to. This has to happen before\n // the upload below, which makes the new revision the latest version and\n // would leave the edits attached to nothing. Best-effort: a failure here\n // costs edit preservation, and must not block the translation itself.\n if (preserveExistingTranslations && !force) {\n try {\n const captured = await captureExistingTranslations({\n documents,\n localeIds: availableLocaleIds,\n secrets,\n context: translationContext,\n branchId,\n });\n if (captured.capturedCount > 0) {\n toast.push({\n title: `Preserved ${captured.capturedCount} existing translation(s) across ${captured.documentCount} document(s)`,\n status: 'info',\n closable: true,\n });\n }\n } catch (error) {\n console.error(\n 'Could not preserve existing translations. Continuing β€” edits made to translated documents may be overwritten by this run.',\n error\n );\n toast.push({\n title:\n 'Existing translations could not be preserved. Translation is continuing, but edits made to translated documents may be overwritten.',\n status: 'warning',\n closable: true,\n });\n }\n }\n\n const transformedDocuments = serializeSourceDocuments();\n\n const uploadResult = await uploadFiles(transformedDocuments, secrets);\n await initProject(uploadResult, { timeout: 600 }, secrets);\n await createJobs(uploadResult, availableLocaleIds, secrets, force);\n\n // Pin the _rev each file was uploaded under. GT status queries need the\n // exact uploaded versionId, and the live _rev moves on (in-place array\n // imports bump it), so status lookups go through getVersionId instead.\n // Persisted to sessionStorage so the pins survive a page refresh.\n const nextUploadedVersions = new Map(uploadedVersions);\n for (const { info } of transformedDocuments) {\n if (info.versionId) {\n nextUploadedVersions.set(info.documentId, info.versionId);\n }\n }\n writeUploadedVersions(uploadedVersionsStorageKey, nextUploadedVersions);\n setUploadedVersions(nextUploadedVersions);\n\n const enqueuedStatusKeys = new Set<string>();\n const enqueuedStableKeys = new Set<string>();\n for (const { info } of transformedDocuments) {\n for (const localeId of availableLocaleIds) {\n enqueuedStatusKeys.add(\n createTranslationStatusKey(\n branchId,\n info.documentId,\n info.versionId ?? '',\n localeId\n )\n );\n enqueuedStableKeys.add(\n createStableTranslationKey(branchId, info.documentId, localeId)\n );\n }\n }\n\n // A key already downloaded this session is skipped by the status\n // query, so re-translating one would leave it outstanding forever:\n // enqueued as pending, never reported ready, never cleared. Drop the\n // markers for everything being retranslated β€” the previous download is\n // superseded by the run starting now.\n setDownloadStatus((prev) => ({\n downloaded: new Set(\n [...prev.downloaded].filter(\n (key) =>\n !enqueuedStatusKeys.has(key) && !enqueuedStableKeys.has(key)\n )\n ),\n failed: new Set(\n [...prev.failed].filter(\n (key) =>\n !enqueuedStatusKeys.has(key) && !enqueuedStableKeys.has(key)\n )\n ),\n skipped: new Set(\n [...prev.skipped].filter(\n (key) =>\n !enqueuedStatusKeys.has(key) && !enqueuedStableKeys.has(key)\n )\n ),\n }));\n\n // Everything just enqueued is outstanding until a refresh reports it\n // ready. Without this the UI cannot tell \"General Translation is\n // working on it\" from \"never translated\" β€” both sit at 0%.\n setPendingTranslations(\n (prev) => new Set([...prev, ...enqueuedStatusKeys])\n );\n\n toast.push({\n title: force\n ? `Retranslating ${documents.length} documents from scratch`\n : `Translation tasks created for ${documents.length} documents`,\n status: 'success',\n closable: true,\n });\n } catch {\n toast.push({\n title:\n 'Translation tasks could not be created. No documents were changed. Try again or check the console for details.',\n status: 'error',\n closable: true,\n });\n } finally {\n setIsBusy(false);\n }\n },\n [\n secrets,\n documents,\n locales,\n schema,\n client,\n branchId,\n preserveExistingTranslations,\n serializeSourceDocuments,\n uploadedVersions,\n uploadedVersionsStorageKey,\n ]\n );\n\n const handleUploadExistingTranslations = useCallback(async () => {\n if (!secrets || documents.length === 0) return;\n\n setIsBusy(true);\n try {\n const availableLocaleIds = locales\n .filter((locale) => locale.enabled !== false)\n .map((locale) => locale.localeId);\n\n const transformedDocuments = serializeSourceDocuments();\n\n // Seed the source files first. uploadTranslations requires the source to\n // exist, and this action exists for projects whose translations predate\n // General Translation, where no source has been uploaded yet. Enqueueing\n // is deliberately skipped so nothing is retranslated.\n await uploadFiles(transformedDocuments, secrets);\n\n const existing = await collectExistingTranslations(\n documents,\n availableLocaleIds,\n translationContext\n );\n const withTranslations = transformedDocuments\n .map((document) => ({\n ...document,\n translations: existing.get(document.info.documentId) ?? [],\n }))\n .filter((document) => document.translations.length > 0);\n\n const response = await uploadTranslations(withTranslations, secrets);\n const count = response?.uploadedFiles.length ?? 0;\n\n toast.push({\n title:\n count > 0\n ? `Uploaded ${count} existing translation(s) across ${withTranslations.length} document(s)`\n : 'No existing translations found to upload',\n status: count > 0 ? 'success' : 'warning',\n closable: true,\n });\n } catch (error) {\n console.error('Error uploading existing translations:', error);\n toast.push({\n title:\n 'Existing translations could not be uploaded. No documents were changed. Try again or check the console for details.',\n status: 'error',\n closable: true,\n });\n } finally {\n setIsBusy(false);\n }\n }, [secrets, documents, locales, client, schema, serializeSourceDocuments]);\n\n const handleImportAll = useCallback(async () => {\n if (!secrets || documents.length === 0 || !branchId) return;\n\n setIsBusy(true);\n\n try {\n const readyFiles = await getReadyFilesForImport(translationStatuses, {\n onSelectedKeys: (keys) => setImportingTranslations(new Set(keys)),\n });\n\n if (readyFiles.length === 0) {\n toast.push({\n title: 'No ready translations to import',\n status: 'warning',\n closable: true,\n });\n return;\n }\n\n setImportProgress({\n current: 0,\n total: readyFiles.length,\n isImporting: true,\n });\n\n const importOptions: ImportOptions = {\n onProgress: (current, total) => {\n setImportProgress({\n current,\n total,\n isImporting: true,\n });\n },\n onImportSuccess: (key) => {\n setImportedTranslations((prev) => new Set([...prev, key]));\n },\n };\n\n const result = await importTranslations(\n readyFiles,\n secrets,\n translationContext,\n importOptions\n );\n\n if (result.successfulImports.length > 0) {\n setDownloadStatus((prev) => ({\n ...prev,\n downloaded: new Set([\n ...prev.downloaded,\n ...result.successfulImports,\n ]),\n }));\n }\n\n toast.push({\n title: `Imported ${result.successCount} translations${result.failureCount > 0 ? `, ${result.failureCount} failed` : ''}`,\n status: result.successCount > 0 ? 'success' : 'error',\n closable: true,\n });\n } catch (error) {\n console.error('Error importing translations:', error);\n toast.push({\n title:\n 'Translations could not be imported. No documents were changed. Try again or check the console for details.',\n status: 'error',\n closable: true,\n });\n } finally {\n setIsBusy(false);\n setImportProgress({ current: 0, total: 0, isImporting: false });\n setImportingTranslations(new Set());\n }\n }, [\n secrets,\n documents,\n translationStatuses,\n downloadStatus,\n translationContext,\n branchId,\n ]);\n\n const getExistingTranslations = useCallback(\n async (\n documentIds: string[],\n localeIds: string[],\n branchId: string\n ): Promise<Set<string>> => {\n const sourceLocale = pluginConfig.getSourceLocale();\n\n const query = `*[\n _type == 'translation.metadata' &&\n translations[language == $sourceLocale][0].value._ref in $documentIds\n ] {\n _rev,\n 'sourceDocId': translations[language == $sourceLocale][0].value._ref,\n 'existingTranslations': translations[language in $localeIds].language\n }`;\n\n const existingMetadata = await client.fetch<\n ExistingTranslationMetadata[]\n >(query, {\n sourceLocale,\n documentIds,\n localeIds,\n });\n\n const existing = new Set<string>();\n existingMetadata.forEach((metadata) => {\n metadata.existingTranslations?.forEach((localeId: string) => {\n if (localeId !== sourceLocale) {\n existing.add(\n createStableTranslationKey(\n branchId,\n metadata.sourceDocId,\n localeId\n )\n );\n }\n });\n });\n\n return existing;\n },\n [client]\n );\n\n const handleImportMissing = useCallback(async () => {\n if (!secrets || documents.length === 0 || !branchId) return;\n\n setIsBusy(true);\n\n try {\n const availableLocaleIds = locales\n .filter((locale) => locale.enabled !== false)\n .map((locale) => locale.localeId);\n\n const documentIds = documents.map(getDocumentPublishedId);\n\n const existingTranslations = await getExistingTranslations(\n documentIds,\n availableLocaleIds,\n branchId\n );\n\n const readyFiles = await getReadyFilesForImport(translationStatuses, {\n onSelectedKeys: (keys) => setImportingTranslations(new Set(keys)),\n filterReadyFiles: (_key, status) =>\n !existingTranslations.has(\n createStableTranslationKey(\n branchId,\n status.fileData.fileId,\n status.fileData.locale\n )\n ),\n });\n\n if (readyFiles.length === 0) {\n toast.push({\n title: 'No missing translations to import',\n status: 'warning',\n closable: true,\n });\n return;\n }\n\n setImportProgress({\n current: 0,\n total: readyFiles.length,\n isImporting: true,\n });\n\n const importOptions: ImportOptions = {\n onProgress: (current, total) => {\n setImportProgress({\n current,\n total,\n isImporting: true,\n });\n },\n onImportSuccess: (key) => {\n setImportedTranslations((prev) => new Set([...prev, key]));\n setExistingTranslations((prev) => new Set([...prev, key]));\n },\n };\n\n const result = await importTranslations(\n readyFiles,\n secrets,\n translationContext,\n importOptions\n );\n\n if (result.successfulImports.length > 0) {\n setDownloadStatus((prev) => ({\n ...prev,\n downloaded: new Set([\n ...prev.downloaded,\n ...result.successfulImports,\n ]),\n }));\n }\n\n toast.push({\n title: `Imported ${result.successCount} missing translations${result.failureCount > 0 ? `, ${result.failureCount} failed` : ''}`,\n status: result.successCount > 0 ? 'success' : 'error',\n closable: true,\n });\n } catch (error) {\n console.error('Error importing missing translations:', error);\n toast.push({\n title:\n 'Missing translations could not be imported. No documents were changed. Try again or check the console for details.',\n status: 'error',\n closable: true,\n });\n } finally {\n setIsBusy(false);\n setImportProgress({ current: 0, total: 0, isImporting: false });\n setImportingTranslations(new Set());\n }\n }, [\n secrets,\n documents,\n locales,\n translationStatuses,\n downloadStatus,\n translationContext,\n getExistingTranslations,\n branchId,\n ]);\n\n const handleGetBranchId = useCallback(\n async (secrets: Secrets) => {\n overrideConfig(secrets);\n const defaultBranch = await api.createBranch({\n branchName: 'main',\n defaultBranch: true,\n });\n setBranchId(defaultBranch.branch.id);\n },\n [secrets]\n );\n\n // `silent` suppresses the success toast. The poll runs every 10 seconds, so\n // only a refresh the user asked for should announce itself.\n const handleRefreshAll = useCallback(\n async ({ silent = false }: { silent?: boolean } = {}) => {\n if (!secrets || documents.length === 0 || !branchId) return;\n setIsRefreshing(true);\n\n try {\n const availableLocaleIds = locales\n .filter((locale) => locale.enabled !== false)\n .map((locale) => locale.localeId);\n\n const fileQueryData: FileProperties[] = [];\n for (const doc of documents) {\n for (const localeId of availableLocaleIds) {\n const documentId = getDocumentPublishedId(doc);\n fileQueryData.push({\n versionId: getVersionId(doc),\n fileId: documentId,\n branchId: branchId,\n locale: localeId,\n });\n }\n }\n\n const readyTranslations = await checkTranslationStatus(\n fileQueryData,\n downloadStatusRef.current,\n secrets\n );\n\n // Built here rather than inside an updater: it derives from the\n // response, not from previous state, and a state updater has to stay\n // pure β€” React may run it more than once.\n const newStatuses = new Map<string, TranslationStatus>();\n\n for (const doc of documents) {\n for (const localeId of availableLocaleIds) {\n const documentId = getDocumentPublishedId(doc);\n const versionId = getVersionId(doc);\n const key = createTranslationStatusKey(\n branchId,\n documentId,\n versionId,\n localeId\n );\n newStatuses.set(key, { progress: 0, isReady: false });\n }\n }\n\n if (Array.isArray(readyTranslations)) {\n for (const translation of readyTranslations) {\n const key = createTranslationStatusKey(\n branchId,\n translation.fileId,\n translation.versionId,\n translation.locale\n );\n newStatuses.set(key, {\n progress: 100,\n isReady: true,\n fileData: {\n versionId: translation.versionId,\n fileId: translation.fileId,\n branchId: translation.branchId,\n locale: translation.locale,\n },\n });\n }\n }\n\n setTranslationStatuses(newStatuses);\n\n // A translation that has arrived is no longer outstanding.\n setPendingTranslations((prev) => {\n if (prev.size === 0) return prev;\n const next = new Set(prev);\n for (const [key, status] of newStatuses) {\n if (status.isReady) next.delete(key);\n }\n return next.size === prev.size ? prev : next;\n });\n\n if (!silent) {\n toast.push({\n title: `Refreshed status for ${documents.length} document(s)`,\n status: 'success',\n closable: true,\n });\n }\n } catch (error) {\n console.error('Error refreshing translation status:', error);\n toast.push({\n title:\n 'Translation status could not be refreshed. Try again before importing.',\n status: 'error',\n closable: true,\n });\n } finally {\n setIsRefreshing(false);\n }\n },\n [secrets, documents, locales, branchId, getVersionId]\n );\n\n const handleImportDocument = useCallback(\n async (documentId: string, versionId: string, localeId: string) => {\n if (!secrets) return;\n\n const key = createTranslationStatusKey(\n branchId,\n documentId,\n versionId,\n localeId\n );\n const status = translationStatuses.get(key);\n\n if (!status?.isReady || !status.fileData) {\n toast.push({\n title: `Translation not ready for ${documentId} (${localeId})`,\n status: 'warning',\n closable: true,\n });\n return;\n }\n\n const document = documents.find(\n (doc) => getDocumentPublishedId(doc) === getPublishedId(documentId)\n );\n\n if (!document) {\n toast.push({\n title: `Document ${documentId} not found`,\n status: 'error',\n closable: true,\n });\n return;\n }\n\n try {\n const downloadedFiles = await downloadTranslations(\n [\n {\n fileId: status.fileData.fileId,\n branchId: status.fileData.branchId,\n versionId: status.fileData.versionId,\n locale: status.fileData.locale,\n },\n ],\n secrets\n );\n\n if (downloadedFiles.length > 0) {\n try {\n const docInfo: GTFile = {\n documentId: getPublishedId(documentId),\n versionId: document._rev,\n };\n\n await importDocument(\n docInfo,\n localeId,\n downloadedFiles[0].data,\n translationContext,\n false\n );\n\n setDownloadStatus((prev) => ({\n ...prev,\n downloaded: new Set([...prev.downloaded, key]),\n }));\n setImportedTranslations((prev) => new Set([...prev, key]));\n setExistingTranslations(\n (prev) =>\n new Set([\n ...prev,\n createStableTranslationKey(branchId, documentId, localeId),\n ])\n );\n\n toast.push({\n title: `Successfully imported translation for ${documentId} (${localeId})`,\n status: 'success',\n closable: true,\n });\n } catch (importError) {\n console.error('Failed to import translation:', importError);\n toast.push({\n title: `Translation for ${documentId} (${localeId}) could not be imported. This document was not changed.`,\n status: 'error',\n closable: true,\n });\n }\n } else {\n toast.push({\n title: `No translation content received for ${documentId}`,\n status: 'warning',\n closable: true,\n });\n }\n } catch (error) {\n console.error('Error importing translation:', error);\n toast.push({\n title: `Translation for ${documentId} could not be imported. This document was not changed.`,\n status: 'error',\n closable: true,\n });\n }\n },\n [secrets, documents, translationContext, translationStatuses, branchId]\n );\n\n const handlePatchDocumentReferences = useCallback(async () => {\n if (!secrets || documents.length === 0) return 0;\n\n setIsBusy(true);\n\n try {\n const availableLocaleIds = locales\n .filter((locale) => locale.enabled !== false)\n .map((locale) => locale.localeId);\n\n const patchTasks: Array<{ doc: SanityDocument; localeId: string }> = [];\n for (const doc of documents) {\n for (const localeId of availableLocaleIds) {\n patchTasks.push({ doc, localeId });\n }\n }\n\n setImportProgress({\n current: 0,\n total: patchTasks.length,\n isImporting: true,\n });\n\n const result = await processBatch(\n patchTasks,\n async ({ doc, localeId }) => {\n const sourceLocale = pluginConfig.getSourceLocale();\n\n // Skip source locale - only process translated documents\n if (localeId === sourceLocale) {\n return { patched: false, doc, localeId, skipped: true };\n }\n\n // Find the translated document for this locale\n const translatedDoc = await findTranslatedDocumentForLocale(\n doc._id,\n localeId,\n client\n );\n\n if (!translatedDoc) {\n return { patched: false, doc, localeId, noTranslation: true };\n }\n\n const resolvedDoc = await resolveRefs(\n translatedDoc,\n localeId,\n client\n );\n\n if (resolvedDoc !== translatedDoc) {\n await commitResolvedRefs(translatedDoc, resolvedDoc, client);\n return { patched: true, doc: translatedDoc, localeId };\n }\n return { patched: false, doc: translatedDoc, localeId };\n },\n {\n onProgress: (current, total) => {\n setImportProgress({\n current,\n total,\n isImporting: true,\n });\n },\n onItemFailure: ({ doc, localeId }, error) => {\n console.error(\n `Failed to patch references for ${doc._id} (${localeId}):`,\n error\n );\n },\n }\n );\n\n const patchedCount = result.successfulItems.filter(\n (item) => item.patched\n ).length;\n\n toast.push({\n title: `Patched references in ${patchedCount} documents${result.failureCount > 0 ? `, ${result.failureCount} failed` : ''}`,\n status:\n patchedCount > 0 || result.failureCount === 0 ? 'success' : 'error',\n closable: true,\n });\n\n return patchedCount;\n } catch (error) {\n console.error('Error patching document references:', error);\n toast.push({\n title:\n 'Document references could not be updated. Imported translations may need to be linked manually.',\n status: 'error',\n closable: true,\n });\n return 0;\n } finally {\n setIsBusy(false);\n setImportProgress({ current: 0, total: 0, isImporting: false });\n }\n }, [secrets, documents, locales, client, branchId]);\n\n const handlePublishAllTranslations = useCallback(async () => {\n if (!secrets || documents.length === 0) return 0;\n\n setIsBusy(true);\n\n try {\n const sourceDocumentIds = documents.map(getDocumentPublishedId);\n const publishedDocumentIds = await client.fetch(\n `*[_id in $sourceDocumentIds]._id`,\n { sourceDocumentIds }\n );\n\n if (publishedDocumentIds.length === 0) {\n toast.push({\n title:\n 'No published source documents found to publish translations for',\n status: 'warning',\n closable: true,\n });\n return 0;\n }\n\n const translationMetadata = await client.fetch<\n TranslationDocumentMetadata[]\n >(TRANSLATION_DOCS_FOR_PUBLISH_QUERY, {\n publishedDocumentIds,\n sourceDocumentIds,\n });\n\n const translationDocIds = new Set<string>();\n translationMetadata.forEach((metadata) => {\n metadata.translationDocs?.forEach((translation) => {\n if (translation.docId) {\n translationDocIds.add(translation.docId);\n }\n });\n });\n\n const publishableIds = Array.from(translationDocIds);\n\n if (publishableIds.length === 0) {\n toast.push({\n title: 'No translation documents found to publish',\n status: 'warning',\n closable: true,\n });\n return 0;\n }\n\n const translatedDocumentIds = await publishTranslations(\n publishableIds,\n client\n );\n\n toast.push({\n title: `Published ${translatedDocumentIds.length} translation documents`,\n status: 'success',\n closable: true,\n });\n\n return translatedDocumentIds.length;\n } catch (error) {\n console.error('Error publishing translations:', error);\n toast.push({\n title:\n 'Translations could not be published. No unpublished source documents were changed.',\n status: 'error',\n closable: true,\n });\n return 0;\n } finally {\n setIsBusy(false);\n }\n }, [secrets, documents, client, branchId]);\n\n useEffect(() => {\n fetchDocuments();\n }, [fetchDocuments]);\n\n useEffect(() => {\n if (secrets) {\n fetchLocales();\n }\n }, [fetchLocales, secrets]);\n\n useEffect(() => {\n if (documents.length > 0 && locales.length > 0) {\n fetchExistingTranslations();\n }\n }, [fetchExistingTranslations]);\n\n useEffect(() => {\n if (\n documents.length > 0 &&\n locales.length > 0 &&\n secrets &&\n !loadingDocuments &&\n branchId\n ) {\n handleRefreshAll({ silent: true });\n }\n }, [\n documents,\n locales,\n secrets,\n loadingDocuments,\n branchId,\n handleRefreshAll,\n ]);\n\n useEffect(() => {\n if (!autoRefresh || documents.length === 0 || !secrets) return;\n\n const interval = setInterval(async () => {\n await handleRefreshAll({ silent: true });\n }, 10000);\n\n return () => clearInterval(interval);\n }, [autoRefresh, documents.length, secrets, handleRefreshAll]);\n\n useEffect(() => {\n setImportedTranslations(new Set(downloadStatus.downloaded));\n }, [downloadStatus.downloaded]);\n\n useEffect(() => {\n if (secrets) {\n handleGetBranchId(secrets);\n }\n }, [secrets, handleGetBranchId]);\n\n const contextValue: TranslationsContextType = {\n // State\n isBusy,\n documents,\n locales,\n autoRefresh,\n autoImport,\n autoPatchReferences,\n autoPublish,\n preserveExistingTranslations,\n loadingDocuments,\n importProgress,\n importedTranslations,\n existingTranslations,\n downloadStatus,\n translationStatuses,\n pendingTranslations,\n importingTranslations,\n isRefreshing,\n loadingSecrets,\n secrets,\n branchId,\n getVersionId,\n\n // Actions\n setLocales,\n setAutoRefresh,\n setAutoImport,\n setAutoPatchReferences,\n setAutoPublish,\n setPreserveExistingTranslations,\n handleTranslateAll,\n handleUploadExistingTranslations,\n handleImportAll,\n handleImportMissing,\n handleRefreshAll,\n handleImportDocument,\n handlePatchDocumentReferences,\n handlePublishAllTranslations,\n };\n\n return (\n <TranslationsContext.Provider value={contextValue}>\n {children}\n </TranslationsContext.Provider>\n );\n};\n","import React from 'react';\nimport { Box, Button, Card, Dialog, Flex, Stack, Text } from '@sanity/ui';\n\ninterface SaveLocalTranslationsDialogProps {\n isOpen: boolean;\n onClose: () => void;\n onConfirm: () => void;\n}\n\nexport const SaveLocalTranslationsDialog: React.FC<\n SaveLocalTranslationsDialogProps\n> = ({ isOpen, onClose, onConfirm }) => {\n if (!isOpen) return null;\n\n return (\n <Dialog\n header='Save local edits'\n id='save-local-translations-dialog'\n onClose={onClose}\n footer={\n <Box padding={3}>\n <Flex gap={2}>\n <Button text='Cancel' mode='ghost' onClick={onClose} />\n <Button text='Turn on' tone='primary' onClick={onConfirm} />\n </Flex>\n </Box>\n }\n >\n <Box padding={4}>\n <Stack gap={4}>\n <Text>\n Before each translation run, the translations currently in Sanity\n are sent to General Translation. Content whose source text has not\n changed is then reused from Sanity instead of being translated\n again, so edits made here are kept.\n </Text>\n\n <Card padding={3} radius={2} tone='caution' border>\n <Stack gap={3}>\n <Text size={1} weight='medium'>\n Sanity becomes the source of truth\n </Text>\n <Text size={1}>\n What is in Sanity replaces whatever General Translation holds\n for that version of the document β€” including a translation that\n has finished but has not been imported yet. Import any pending\n translations before turning this on.\n </Text>\n </Stack>\n </Card>\n\n <Text size={1} muted>\n This applies to translation runs started from this Studio session.\n To send them without starting a run, use Save Local Edits.\n </Text>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","import { pluginConfig } from '../adapter/core';\nimport { version as PACKAGE_VERSION } from '../../package.json';\nimport type { Secrets } from '../types';\nimport type { TranslationPreferences } from '../adapter/types';\nimport type { TranslationSummary } from './translationSummary';\n\nexport type DebugInfo = {\n package: { name: 'gt-sanity'; version: string };\n sanity: { projectId?: string; dataset?: string };\n generalTranslation: {\n projectId?: string;\n /** Whether the secrets document supplied an API key. Never the key. */\n apiKeyConfigured: boolean;\n secretsNamespace: string;\n secretsDocumentFound: boolean;\n branchId?: string;\n };\n locales: { sourceLocale: string; targetLocales: string[] };\n documents: {\n translationLevel: string;\n translateDocuments: unknown[];\n fieldLevelDocuments: unknown[];\n languageField: string;\n singletons: string[];\n };\n fieldRules: {\n ignoreFields: unknown[];\n dedupeFields: unknown[];\n skipFields: unknown[];\n additionalStopTypes: string[];\n };\n /**\n * Where the translations actually are. A high `draftOnly` with `published`\n * at zero means they exist but are invisible to anything reading the\n * published perspective.\n */\n translations: TranslationSummary;\n /** Effective values, after any stored user choice overrides plugin config. */\n preferences: TranslationPreferences;\n customization: {\n additionalSerializers: string[];\n additionalDeserializers: string[];\n additionalBlockDeserializers: number;\n };\n};\n\nexport type BuildDebugInfoInput = {\n secrets: Secrets | null;\n preferences: TranslationPreferences;\n translations: TranslationSummary;\n sanityProjectId?: string;\n sanityDataset?: string;\n branchId?: string;\n};\n\n/**\n * Collects the plugin's effective configuration for support and bug reports.\n *\n * The API key is never included, only whether one is set β€” the result is built\n * to be pasted into a ticket. Functions and serializer implementations are\n * reduced to names and counts so the result stays JSON-serializable.\n */\nexport function buildDebugInfo({\n secrets,\n preferences,\n translations,\n sanityProjectId,\n sanityDataset,\n branchId,\n}: BuildDebugInfoInput): DebugInfo {\n const deserializers = pluginConfig.getAdditionalDeserializers();\n const deserializerTypes = deserializers?.types ?? {};\n\n return {\n package: { name: 'gt-sanity', version: PACKAGE_VERSION },\n sanity: { projectId: sanityProjectId, dataset: sanityDataset },\n generalTranslation: {\n projectId: secrets?.project,\n apiKeyConfigured: Boolean(secrets?.secret),\n secretsNamespace: pluginConfig.getSecretsNamespace(),\n secretsDocumentFound: secrets !== null,\n branchId,\n },\n locales: {\n sourceLocale: pluginConfig.getSourceLocale(),\n targetLocales: pluginConfig.getLocales(),\n },\n documents: {\n translationLevel: pluginConfig.getTranslationLevel(),\n translateDocuments: pluginConfig.getTranslateDocuments(),\n fieldLevelDocuments: pluginConfig.getFieldLevelDocuments(),\n languageField: pluginConfig.getLanguageField(),\n singletons: pluginConfig.getSingletons(),\n },\n fieldRules: {\n ignoreFields: pluginConfig.getIgnoreFields(),\n dedupeFields: pluginConfig.getDedupeFields(),\n skipFields: pluginConfig.getSkipFields(),\n additionalStopTypes: pluginConfig.getAdditionalStopTypes(),\n },\n translations,\n preferences,\n customization: {\n additionalSerializers: Object.keys(\n pluginConfig.getAdditionalSerializers()?.types ?? {}\n ),\n additionalDeserializers: Object.keys(deserializerTypes),\n additionalBlockDeserializers:\n pluginConfig.getAdditionalBlockDeserializers()?.length ?? 0,\n },\n };\n}\n\nexport function formatDebugInfo(info: DebugInfo): string {\n return JSON.stringify(info, null, 2);\n}\n","import type { SanityClient, SanityDocument } from 'sanity';\nimport { pluginConfig } from '../adapter/core';\nimport { getDocumentPublishedId } from './documentIds';\n\nexport type TranslationSummary = {\n /** Source documents the plugin is configured to translate. */\n documentsChecked: number;\n /** Source documents times target locales. */\n expected: number;\n /** Translated documents recorded in `translation.metadata`. */\n found: number;\n /** Found translations that exist only as a draft. */\n draftOnly: number;\n /** Found translations that have a published version. */\n published: number;\n /** Expected translations with no `translation.metadata` entry. */\n missing: number;\n};\n\nexport const EMPTY_TRANSLATION_SUMMARY: TranslationSummary = {\n documentsChecked: 0,\n expected: 0,\n found: 0,\n draftOnly: 0,\n published: 0,\n missing: 0,\n};\n\ntype MetadataEntry = { targets?: { language?: string; id?: string }[] };\n\nexport type SummarizeInput = {\n documentCount: number;\n targetLocaleCount: number;\n translatedIds: string[];\n publishedIds: string[];\n draftIds: string[];\n};\n\n/**\n * Counts translations by where they exist.\n *\n * A translation with no published version is only visible to a reader on the\n * drafts perspective, which is why `draftOnly` is reported separately rather\n * than folded into `found`.\n */\nexport function summarizeTranslations({\n documentCount,\n targetLocaleCount,\n translatedIds,\n publishedIds,\n draftIds,\n}: SummarizeInput): TranslationSummary {\n const unique = Array.from(new Set(translatedIds));\n const publishedSet = new Set(publishedIds);\n const draftSet = new Set(draftIds);\n\n const published = unique.filter((id) => publishedSet.has(id)).length;\n const draftOnly = unique.filter(\n (id) => !publishedSet.has(id) && draftSet.has(`drafts.${id}`)\n ).length;\n const expected = documentCount * targetLocaleCount;\n\n return {\n documentsChecked: documentCount,\n expected,\n found: unique.length,\n draftOnly,\n published,\n missing: Math.max(0, expected - unique.length),\n };\n}\n\n/**\n * Reads `translation.metadata` for the given documents and reports how many\n * translations exist, and whether they are published or draft-only.\n */\nexport async function collectTranslationSummary(\n documents: SanityDocument[],\n client: SanityClient\n): Promise<TranslationSummary> {\n const documentIds = documents.map(getDocumentPublishedId);\n const targetLocales = pluginConfig.getLocales();\n\n if (documentIds.length === 0) {\n return EMPTY_TRANSLATION_SUMMARY;\n }\n\n // Only the configured target locales are counted. Metadata can also hold\n // entries for the source and for locales dropped from the configuration\n // since, and neither is something this reports on.\n //\n // The metadata document is found by reference rather than by its\n // source-language entry: that entry records whatever `sourceLocale` was set\n // when it was created, so a project that later changed it would match none\n // of its own translations.\n const entries = await client.fetch<MetadataEntry[]>(\n `*[_type == 'translation.metadata' && references($documentIds)]{\n 'targets': translations[language in $targetLocales && defined(value._ref)]{\n language,\n 'id': value._ref\n }\n }`,\n { documentIds, targetLocales }\n );\n\n const translatedIds = entries\n .flatMap((entry) => entry.targets ?? [])\n .map((target) => target.id)\n .filter((id): id is string => Boolean(id));\n\n if (translatedIds.length === 0) {\n return summarizeTranslations({\n documentCount: documentIds.length,\n targetLocaleCount: targetLocales.length,\n translatedIds: [],\n publishedIds: [],\n draftIds: [],\n });\n }\n\n const unique = Array.from(new Set(translatedIds));\n const existence = await client.fetch<{\n publishedIds: string[];\n draftIds: string[];\n }>(\n `{\n 'publishedIds': *[_id in $ids]._id,\n 'draftIds': *[_id in $draftIds]._id\n }`,\n { ids: unique, draftIds: unique.map((id) => `drafts.${id}`) }\n );\n\n return summarizeTranslations({\n documentCount: documentIds.length,\n targetLocaleCount: targetLocales.length,\n translatedIds: unique,\n publishedIds: existence?.publishedIds ?? [],\n draftIds: existence?.draftIds ?? [],\n });\n}\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { Box, Button, Card, Dialog, Flex, Stack } from '@sanity/ui';\nimport { Code } from '@sanity/ui/code';\nimport { ClipboardIcon } from '@sanity/icons/Clipboard';\nimport { useClient } from '../../hooks/useClient';\nimport { useTranslations } from '../TranslationsProvider';\nimport { buildDebugInfo, formatDebugInfo } from '../../utils/debugInfo';\nimport {\n collectTranslationSummary,\n EMPTY_TRANSLATION_SUMMARY,\n type TranslationSummary,\n} from '../../utils/translationSummary';\n\ninterface DebugInfoDialogProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport const DebugInfoDialog: React.FC<DebugInfoDialogProps> = ({\n isOpen,\n onClose,\n}) => {\n const {\n secrets,\n documents,\n branchId,\n autoRefresh,\n autoImport,\n autoPatchReferences,\n autoPublish,\n preserveExistingTranslations,\n } = useTranslations();\n const client = useClient();\n const [copied, setCopied] = useState(false);\n const [translations, setTranslations] = useState<TranslationSummary>(\n EMPTY_TRANSLATION_SUMMARY\n );\n\n const { projectId, dataset } = client.config();\n\n const serialized = useMemo(\n () =>\n formatDebugInfo(\n buildDebugInfo({\n secrets,\n preferences: {\n autoRefresh,\n autoImport,\n autoPatchReferences,\n autoPublish,\n preserveExistingTranslations,\n },\n translations,\n sanityProjectId: projectId,\n sanityDataset: dataset,\n branchId,\n })\n ),\n [\n secrets,\n translations,\n branchId,\n projectId,\n dataset,\n autoRefresh,\n autoImport,\n autoPatchReferences,\n autoPublish,\n preserveExistingTranslations,\n ]\n );\n\n // Reads the dataset, so it runs when the dialog opens rather than on every\n // status poll. Failures leave the zeroed summary rather than blocking the\n // rest of the debug output.\n useEffect(() => {\n if (!isOpen) return;\n let cancelled = false;\n collectTranslationSummary(documents, client)\n .then((summary) => {\n if (!cancelled) setTranslations(summary);\n })\n .catch(() => {\n if (!cancelled) setTranslations(EMPTY_TRANSLATION_SUMMARY);\n });\n return () => {\n cancelled = true;\n };\n }, [isOpen, documents, client]);\n\n if (!isOpen) return null;\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(serialized);\n setCopied(true);\n } catch {\n // Clipboard unavailable (insecure origin, denied permission) β€” the text\n // is on screen and selectable.\n setCopied(false);\n }\n };\n\n return (\n <Dialog\n header='Debug info'\n id='gt-debug-info-dialog'\n onClose={onClose}\n width={2}\n footer={\n <Box padding={3}>\n <Flex gap={2} justify='space-between' align='center'>\n <Button\n icon={ClipboardIcon}\n text={copied ? 'Copied' : 'Copy'}\n tone={copied ? 'positive' : 'default'}\n mode='ghost'\n onClick={handleCopy}\n />\n <Button text='Close' mode='ghost' onClick={onClose} />\n </Flex>\n </Box>\n }\n >\n <Box padding={4}>\n <Stack gap={4}>\n <Card\n padding={3}\n radius={2}\n tone='transparent'\n border\n overflow='auto'\n style={{ maxHeight: '50vh' }}\n >\n <Code size={0} language='json'>\n {serialized}\n </Code>\n </Card>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","import { Badge, Flex, Text } from '@sanity/ui';\nimport { getLocaleDisplay } from '../../utils/localeDisplay';\n\ntype LocaleLabelProps = {\n localeId: string;\n size?: number;\n weight?: 'regular' | 'medium' | 'semibold' | 'bold';\n};\n\n/**\n * Locale display used across the plugin UI: flag emoji, plain language name,\n * and the locale code in a muted chip β€” e.g. `πŸ‡ΊπŸ‡Έ English [en-US]`.\n */\nexport const LocaleLabel = ({\n localeId,\n size = 1,\n weight = 'medium',\n}: LocaleLabelProps) => {\n const { emoji, name, code, verbatim } = getLocaleDisplay(localeId);\n\n return (\n <Flex align='center' gap={2}>\n {emoji && (\n <Text size={size} aria-hidden>\n {emoji}\n </Text>\n )}\n <Text size={size} weight={weight}>\n {name}\n </Text>\n {!verbatim && (\n <Badge fontSize={0} radius={2}>\n {code}\n </Badge>\n )}\n </Flex>\n );\n};\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\nimport { useCallback, useState } from 'react';\nimport { Badge, Box, Button, Flex, Grid, Spinner, Text } from '@sanity/ui';\nimport { CheckmarkCircleIcon } from '@sanity/icons/CheckmarkCircle';\nimport { DownloadIcon } from '@sanity/icons/Download';\nimport { LocaleLabel } from './LocaleLabel';\n\n/**\n * What a locale row can be showing.\n *\n * General Translation reports a translation as complete or not, with nothing in\n * between, so a percentage was only ever 0 or 100 β€” and 0 read identically for\n * \"never translated\" and \"being translated right now\".\n */\nexport type LanguageStatusState =\n | 'not-translated'\n | 'translating'\n | 'ready'\n | 'imported';\n\ntype LanguageStatusProps = {\n localeId: string;\n state: LanguageStatusState;\n importFile: () => Promise<void>;\n /**\n * This locale is part of an import running elsewhere, such as Import All.\n * The row's own button state only covers a click on that button, so without\n * this a bulk import leaves every row looking idle until it finishes.\n */\n isImporting?: boolean;\n};\n\nconst STATE_LABEL: Record<LanguageStatusState, string> = {\n 'not-translated': 'Not translated',\n translating: 'Translating…',\n ready: 'Ready to import',\n imported: 'Imported',\n};\n\nexport const LanguageStatus = ({\n localeId,\n state,\n importFile,\n isImporting = false,\n}: LanguageStatusProps) => {\n const [isSelfImporting, setIsSelfImporting] = useState(false);\n // A bulk import reports every queued locale at once and only clears the set\n // when the whole run ends, so a row that has already landed must stop\n // reporting itself as in progress on its own.\n const isBusy = (isSelfImporting || isImporting) && state !== 'imported';\n\n const handleImport = useCallback(async () => {\n setIsSelfImporting(true);\n try {\n await importFile();\n } finally {\n setIsSelfImporting(false);\n }\n }, [importFile]);\n\n return (\n <Grid gridTemplateColumns={5} gap={3} paddingX={3} paddingY={2}>\n <Flex gridColumnStart={1} gridColumnEnd={3} align='center'>\n <LocaleLabel localeId={localeId} />\n </Flex>\n\n <Flex gridColumnStart={3} gridColumnEnd={5} align='center' gap={2}>\n {(state === 'translating' || isBusy) && <Spinner size={1} muted />}\n <Text size={1} muted={state !== 'ready'}>\n {isBusy ? 'Importing…' : STATE_LABEL[state]}\n </Text>\n </Flex>\n\n <Flex\n gridColumnStart={5}\n gridColumnEnd={6}\n align='center'\n justify='flex-end'\n >\n {state === 'imported' ? (\n <Badge tone='positive' fontSize={0} radius={2}>\n <Flex align='center' gap={1}>\n <CheckmarkCircleIcon />\n <Box>Imported</Box>\n </Flex>\n </Badge>\n ) : (\n <Button\n style={{ width: '100%' }}\n mode='ghost'\n fontSize={1}\n padding={2}\n onClick={handleImport}\n text={isBusy ? 'Importing…' : 'Import'}\n loading={isBusy}\n icon={DownloadIcon}\n disabled={isBusy || state !== 'ready'}\n />\n )}\n </Flex>\n </Grid>\n );\n};\n","import type { LanguageStatusState } from '../components/shared/LanguageStatus';\nimport type { TranslationStatus } from '../adapter/types';\n\nexport type ResolveLanguageStatusInput = {\n status?: TranslationStatus;\n isImported: boolean;\n isPending: boolean;\n};\n\n/**\n * Resolves what a locale row shows.\n *\n * `imported` wins over everything: once a translation is in Sanity, the status\n * query stops returning it, so a later refresh reports it as not ready.\n */\nexport function resolveLanguageStatusState({\n status,\n isImported,\n isPending,\n}: ResolveLanguageStatusInput): LanguageStatusState {\n if (isImported) return 'imported';\n if (status?.isReady) return 'ready';\n if (isPending) return 'translating';\n return 'not-translated';\n}\n","import { useCallback } from 'react';\nimport { Button, Checkbox, Flex } from '@sanity/ui';\nimport { TranslationLocale } from '../../types';\nimport { LocaleLabel } from './LocaleLabel';\n\ntype LocaleCheckboxProps = {\n locale: TranslationLocale;\n toggle: (locale: string, shouldEnable: boolean) => void;\n checked: boolean;\n};\n\nexport const LocaleCheckbox = ({\n locale,\n toggle,\n checked,\n}: LocaleCheckboxProps) => {\n const onClick = useCallback(\n () => toggle(locale.localeId, !checked),\n [locale.localeId, toggle, checked]\n );\n\n return (\n <Button\n mode='ghost'\n onClick={onClick}\n style={{ cursor: 'pointer' }}\n padding={3}\n >\n <Flex align='center' gap={3}>\n <Checkbox\n style={{ pointerEvents: 'none' }}\n onChange={onClick}\n checked={checked}\n />\n <LocaleLabel localeId={locale.localeId} />\n </Flex>\n </Button>\n );\n};\n","// adapted from https://github.com/sanity-io/sanity-translations-tab. See LICENSE.md for more details.\n\n/**\n * Add cleanup function to cancel async tasks\n */\n\nimport { useMemo, useState, useCallback, useEffect, useRef } from 'react';\nimport { Stack, Text, Card, Button, Grid, Flex, Switch } from '@sanity/ui';\nimport { Tooltip } from '@sanity/ui/tooltip';\nimport { useToast } from '@sanity/ui/toast';\nimport { pluginConfig } from '../../adapter/core';\nimport { SaveLocalTranslationsDialog } from '../page/SaveLocalTranslationsDialog';\nimport { DebugInfoDialog } from '../page/DebugInfoDialog';\nimport { version as PACKAGE_VERSION } from '../../../package.json';\nimport { useTranslations } from '../TranslationsProvider';\nimport { LanguageStatus } from '../shared/LanguageStatus';\nimport { resolveLanguageStatusState } from '../../utils/languageStatusState';\nimport { LocaleCheckbox } from '../shared/LocaleCheckbox';\nimport { DownloadIcon } from '@sanity/icons/Download';\nimport { LinkIcon } from '@sanity/icons/Link';\nimport { PublishIcon } from '@sanity/icons/Publish';\nimport { RefreshIcon } from '@sanity/icons/Refresh';\nimport { TranslateIcon } from '@sanity/icons/Translate';\nimport { UploadIcon } from '@sanity/icons/Upload';\nimport {\n createTranslationStatusKey,\n getDocumentPublishedId,\n} from '../../utils/documentIds';\n\nexport const TranslationView = () => {\n const {\n documents,\n locales,\n translationStatuses,\n pendingTranslations,\n importingTranslations,\n branchId,\n isBusy,\n handleTranslateAll,\n handleUploadExistingTranslations,\n handleImportDocument,\n handleRefreshAll,\n isRefreshing,\n importedTranslations,\n setLocales,\n handlePatchDocumentReferences,\n handlePublishAllTranslations,\n autoRefresh,\n setAutoRefresh,\n autoImport,\n setAutoImport,\n autoPatchReferences,\n setAutoPatchReferences,\n autoPublish,\n setAutoPublish,\n preserveExistingTranslations,\n setPreserveExistingTranslations,\n getVersionId,\n } = useTranslations();\n\n const [isImporting, setIsImporting] = useState(false);\n const [isPublishing, setIsPublishing] = useState(false);\n const [isUploadingExisting, setIsUploadingExisting] = useState(false);\n const [isSaveLocalDialogOpen, setIsSaveLocalDialogOpen] = useState(false);\n const [isDebugInfoDialogOpen, setIsDebugInfoDialogOpen] = useState(false);\n\n const toast = useToast();\n\n // Get the single document (first document in single document mode)\n const document = documents[0];\n\n // Extract the current document's language from the language field\n const currentDocumentLanguage = useMemo(() => {\n if (!document) return null;\n\n // Get the language from the document's language field\n const languageField = pluginConfig.getLanguageField();\n const documentLanguage = document[languageField];\n\n // If no language field is set, assume it's the source language\n return documentLanguage || pluginConfig.getSourceLocale();\n }, [document]);\n\n // Only show translation components if we're on a source language document\n const shouldShowTranslationComponents = useMemo(() => {\n if (!currentDocumentLanguage) return false;\n return currentDocumentLanguage === pluginConfig.getSourceLocale();\n }, [currentDocumentLanguage]);\n\n // Get available locales (excluding source locale)\n const availableLocales = useMemo(() => {\n const sourceLocale = pluginConfig.getSourceLocale();\n return locales.filter(\n (locale) => locale.enabled !== false && locale.localeId !== sourceLocale\n );\n }, [locales]);\n\n // Every configured target locale, regardless of selection. The status\n // section renders this stable list so toggling locale checkboxes doesn't\n // add/remove rows and shift the layout.\n const statusLocales = useMemo(() => {\n const sourceLocale = pluginConfig.getSourceLocale();\n return locales.filter((locale) => locale.localeId !== sourceLocale);\n }, [locales]);\n\n // Get document ID for status tracking\n const documentId = useMemo(() => {\n if (!document) return null;\n return getDocumentPublishedId(document);\n }, [document]);\n\n // Version the status entries are keyed under: the _rev pinned at upload\n // time when available, so importing in place (which bumps the live _rev)\n // doesn't detach the UI from the statuses of the uploaded version.\n const versionId = useMemo(() => {\n if (!document) return null;\n return getVersionId(document);\n }, [document, getVersionId]);\n\n // Translations that were already complete when this dialog opened. Auto-import\n // means \"import a translation that finishes while I am watching\", so these are\n // left alone: importing them would rewrite translated documents β€” discarding\n // any edits made to them β€” every time the dialog is opened. Reset on Translate,\n // so a fresh run's results are imported even for a locale that already had one.\n const alreadyCompleteRef = useRef<Set<string> | null>(null);\n\n const statusKeyFor = useCallback(\n (localeId: string) =>\n createTranslationStatusKey(\n branchId,\n documentId ?? '',\n versionId ?? '',\n localeId\n ),\n [branchId, documentId, versionId]\n );\n\n if (\n alreadyCompleteRef.current === null &&\n documentId &&\n versionId &&\n translationStatuses.size > 0\n ) {\n alreadyCompleteRef.current = new Set(\n statusLocales\n .map((locale) => statusKeyFor(locale.localeId))\n .filter((key) => translationStatuses.get(key)?.isReady)\n );\n }\n\n // The per-locale rows already read \"Translating…\"; this only guards the\n // button against enqueueing the same run twice.\n const isWaitingOnTranslations = statusLocales.some((locale) =>\n pendingTranslations.has(statusKeyFor(locale.localeId))\n );\n\n // Unified import functionality\n const handleImportTranslations = useCallback(\n async (options: { autoOnly?: boolean } = {}) => {\n const { autoOnly = false } = options;\n\n // Check preconditions\n if (isImporting || !documentId || !versionId) return;\n if (autoOnly && !autoImport) return;\n\n // Find translations ready to import (any configured locale, not just\n // the ones currently selected for translation)\n const readyTranslations = statusLocales.filter((locale) => {\n const key = createTranslationStatusKey(\n branchId,\n documentId,\n versionId,\n locale.localeId\n );\n const status = translationStatuses.get(key);\n if (!status?.isReady || importedTranslations.has(key)) return false;\n return !(autoOnly && alreadyCompleteRef.current?.has(key));\n });\n\n if (readyTranslations.length === 0) return;\n\n setIsImporting(true);\n try {\n // Import sequentially: internationalized-array imports patch this same\n // document in place, so concurrent locale imports would overwrite each\n // other and only the last locale would survive.\n for (const locale of readyTranslations) {\n await handleImportDocument(documentId, versionId, locale.localeId);\n }\n\n // Auto patch document references if enabled\n if (autoPatchReferences) {\n await handlePatchDocumentReferences();\n }\n\n // Auto publish translations if enabled\n if (autoPublish) {\n await handlePublishAllTranslations();\n }\n } finally {\n setIsImporting(false);\n }\n },\n [\n autoImport,\n isImporting,\n documentId,\n versionId,\n statusLocales,\n translationStatuses,\n importedTranslations,\n handleImportDocument,\n autoPatchReferences,\n handlePatchDocumentReferences,\n autoPublish,\n handlePublishAllTranslations,\n toast,\n ]\n );\n\n // Check for completed translations on status updates (auto-import)\n useEffect(() => {\n handleImportTranslations({ autoOnly: true });\n }, [handleImportTranslations]);\n\n // Locale toggle functionality\n const toggleLocale = useCallback(\n (localeId: string, shouldEnable: boolean) => {\n const updatedLocales = locales.map((locale) =>\n locale.localeId === localeId\n ? { ...locale, enabled: shouldEnable }\n : locale\n );\n setLocales(updatedLocales);\n },\n [locales, setLocales]\n );\n\n const toggleAllLocales = useCallback(() => {\n const sourceLocale = pluginConfig.getSourceLocale();\n const nonSourceLocales = locales.filter(\n (locale) => locale.localeId !== sourceLocale\n );\n const allEnabled = nonSourceLocales.every(\n (locale) => locale.enabled === true || locale.enabled === undefined\n );\n\n const updatedLocales = locales.map((locale) =>\n locale.localeId === sourceLocale\n ? locale // Don't change source locale\n : { ...locale, enabled: !allEnabled }\n );\n setLocales(updatedLocales);\n }, [locales, setLocales]);\n\n // Show message if we're not on a source language document\n if (!shouldShowTranslationComponents) {\n return (\n <Card padding={4} tone='neutral' border>\n <Text size={1} muted>\n Translation tools are only available for{' '}\n <code>{pluginConfig.getSourceLocale()}</code> documents.\n </Text>\n </Card>\n );\n }\n\n return (\n <Stack gap={6} padding={4}>\n {/* Translate Section */}\n <Stack gap={4}>\n <Text as='h2' weight='semibold' size={2}>\n Translate\n </Text>\n\n {/* Locale Selection */}\n <Stack gap={3}>\n <Flex align='center' justify='space-between'>\n <Text weight='semibold' size={1}>\n {availableLocales.length === 1\n ? 'Select locale'\n : 'Select locales'}\n </Text>\n <Button\n fontSize={1}\n padding={2}\n mode='ghost'\n text='Toggle All'\n onClick={toggleAllLocales}\n />\n </Flex>\n\n <Grid gridTemplateColumns={[1, 1, 2, 3]} gap={1}>\n {locales\n .filter(\n (locale) => locale.localeId !== pluginConfig.getSourceLocale()\n )\n .map((locale) => (\n <LocaleCheckbox\n key={locale.localeId}\n locale={locale}\n toggle={toggleLocale}\n checked={\n locale.enabled === true || locale.enabled === undefined\n }\n />\n ))}\n </Grid>\n </Stack>\n\n <Button\n onClick={() => {\n // A new run's results should import even for locales that already\n // had a translation when the dialog opened.\n alreadyCompleteRef.current = new Set();\n handleTranslateAll();\n }}\n disabled={\n isBusy || isWaitingOnTranslations || !availableLocales.length\n }\n icon={TranslateIcon}\n text={isWaitingOnTranslations ? 'Translating…' : 'Translate'}\n loading={(isBusy && !isUploadingExisting) || isWaitingOnTranslations}\n />\n </Stack>\n\n <SaveLocalTranslationsDialog\n isOpen={isSaveLocalDialogOpen}\n onClose={() => setIsSaveLocalDialogOpen(false)}\n onConfirm={() => {\n setPreserveExistingTranslations(true);\n setIsSaveLocalDialogOpen(false);\n }}\n />\n\n {/* Translation Status Section */}\n {documentId && versionId && statusLocales.length > 0 && (\n <Stack gap={4}>\n <Flex align='center' justify='space-between'>\n <Text as='h2' weight='semibold' size={2}>\n Translation Status\n </Text>\n <Flex gap={3} align='center'>\n <Flex gap={2} align='center'>\n <Text size={1}>Auto-refresh</Text>\n <Switch\n checked={autoRefresh}\n onChange={() => setAutoRefresh(!autoRefresh)}\n />\n </Flex>\n <Button\n fontSize={1}\n padding={2}\n mode='ghost'\n icon={RefreshIcon}\n text='Refresh'\n loading={isRefreshing}\n onClick={() => handleRefreshAll()}\n disabled={isRefreshing || isBusy}\n />\n </Flex>\n </Flex>\n\n <Card border radius={3} paddingY={1}>\n {statusLocales.map((locale) => {\n const key = createTranslationStatusKey(\n branchId,\n documentId,\n versionId,\n locale.localeId\n );\n const status = translationStatuses.get(key);\n const isImported = importedTranslations.has(key);\n\n return (\n <LanguageStatus\n key={key}\n localeId={locale.localeId}\n state={resolveLanguageStatusState({\n status,\n isImported,\n isPending: pendingTranslations.has(key),\n })}\n isImporting={importingTranslations.has(key)}\n importFile={async () => {\n if (!isImported && status?.isReady) {\n await handleImportDocument(\n documentId,\n versionId,\n locale.localeId\n );\n }\n }}\n />\n );\n })}\n </Card>\n\n {/* Import Controls */}\n <Stack gap={3}>\n <Flex gap={2} align='center' justify='flex-start'>\n <Button\n mode='ghost'\n onClick={async () => {\n setIsUploadingExisting(true);\n try {\n await handleUploadExistingTranslations();\n } finally {\n setIsUploadingExisting(false);\n }\n }}\n disabled={isBusy || !availableLocales.length}\n icon={UploadIcon}\n text='Save Local Edits'\n loading={isUploadingExisting}\n style={{ minWidth: '180px' }}\n />\n <Flex gap={2} align='center'>\n <Switch\n checked={preserveExistingTranslations}\n onChange={() => {\n // Turning it on changes what wins on a conflict, so explain\n // before enabling; turning it off is safe.\n if (preserveExistingTranslations) {\n setPreserveExistingTranslations(false);\n } else {\n setIsSaveLocalDialogOpen(true);\n }\n }}\n />\n <Text size={1}>Save local edits before translating</Text>\n </Flex>\n </Flex>\n <Flex gap={3} align='center' justify='space-between'>\n <Flex gap={2} align='center'>\n <Button\n mode='ghost'\n onClick={() => handleImportTranslations()}\n text='Import All'\n loading={isImporting}\n icon={DownloadIcon}\n disabled={\n isImporting ||\n statusLocales.every((locale) => {\n const key = createTranslationStatusKey(\n branchId,\n documentId,\n versionId,\n locale.localeId\n );\n const status = translationStatuses.get(key);\n return !status?.isReady || importedTranslations.has(key);\n })\n }\n style={{ minWidth: '180px' }}\n />\n <Flex gap={2} align='center'>\n <Switch\n checked={autoImport}\n onChange={() => setAutoImport(!autoImport)}\n disabled={isImporting}\n />\n <Text size={1}>Auto-import when complete</Text>\n </Flex>\n </Flex>\n {/* Counted against every configured locale. The number of\n currently-ready translations decays to zero as they are\n imported, because a downloaded file drops out of the status\n query β€” which made the old denominator read \"6/0\". */}\n <Text size={1} muted>\n {\n statusLocales.filter((locale) =>\n importedTranslations.has(statusKeyFor(locale.localeId))\n ).length\n }{' '}\n of {statusLocales.length} imported\n </Text>\n </Flex>\n\n <Flex gap={2} align='center' justify='flex-start'>\n <Tooltip\n placement='top'\n content={`Replaces references to ${pluginConfig.getSourceLocale()} documents in this document with the corresponding translated document reference`}\n >\n <Button\n mode='ghost'\n onClick={async () => {\n await handlePatchDocumentReferences();\n }}\n text='Patch References'\n loading={isBusy}\n icon={LinkIcon}\n disabled={isBusy || isImporting}\n style={{ minWidth: '180px' }}\n />\n </Tooltip>\n <Flex gap={2} align='center'>\n <Switch\n checked={autoPatchReferences}\n onChange={() => setAutoPatchReferences(!autoPatchReferences)}\n disabled={isImporting || isBusy}\n />\n <Text size={1}>Auto-patch after import</Text>\n </Flex>\n </Flex>\n\n <Flex gap={2} align='center' justify='flex-start'>\n <Tooltip\n placement='top'\n content='Publishes all translations (if the source document is published)'\n >\n <Button\n mode='ghost'\n onClick={async () => {\n setIsPublishing(true);\n try {\n await handlePublishAllTranslations();\n } finally {\n setIsPublishing(false);\n }\n }}\n text='Publish Translations'\n loading={isPublishing}\n icon={PublishIcon}\n disabled={isBusy || isPublishing || isImporting}\n style={{ minWidth: '180px' }}\n />\n </Tooltip>\n <Flex gap={2} align='center'>\n <Switch\n checked={autoPublish}\n onChange={() => setAutoPublish(!autoPublish)}\n disabled={isPublishing || isImporting || isBusy}\n />\n <Text size={1}>Auto-publish after import</Text>\n </Flex>\n </Flex>\n </Stack>\n </Stack>\n )}\n\n <Card borderTop paddingTop={3}>\n <Flex align='center' justify='flex-end' gap={2}>\n <Text size={1} muted>\n gt-sanity v{PACKAGE_VERSION}\n </Text>\n <Button\n fontSize={1}\n padding={2}\n mode='bleed'\n text='Debug info'\n onClick={() => setIsDebugInfoDialogOpen(true)}\n />\n </Flex>\n </Card>\n\n <DebugInfoDialog\n isOpen={isDebugInfoDialogOpen}\n onClose={() => setIsDebugInfoDialogOpen(false)}\n />\n </Stack>\n );\n};\n","import React, { useState } from 'react';\nimport { DocumentActionComponent } from 'sanity';\nimport { TranslateIcon } from '@sanity/icons/Translate';\nimport { BaseTranslationWrapper } from '../components/shared/BaseTranslationWrapper';\nimport { TranslationsProvider } from '../components/TranslationsProvider';\nimport { TranslationView } from '../components/tab/TranslationView';\n\nexport const translateAction: DocumentActionComponent = (props) => {\n const [dialogOpen, setDialogOpen] = useState(false);\n const document = props.draft || props.published;\n\n return {\n label: 'Translate',\n icon: TranslateIcon,\n tone: 'primary',\n onHandle: () => setDialogOpen(true),\n dialog: dialogOpen\n ? {\n type: 'dialog' as const,\n header: 'Translations',\n onClose: () => setDialogOpen(false),\n content: (\n <BaseTranslationWrapper showContainer={false}>\n <TranslationsProvider singleDocument={document}>\n <TranslationView />\n </TranslationsProvider>\n </BaseTranslationWrapper>\n ),\n }\n : null,\n };\n};\n","import { getLocaleProperties } from 'generaltranslation';\nimport type { CustomMapping } from 'generaltranslation/types';\nimport { formatLocalePropertiesLabel } from '../utils/localeDisplay';\nimport type { PluginOptions } from 'sanity';\nimport { internationalizedArray } from 'sanity-plugin-internationalized-array';\nimport type { PluginConfig as InternationalizedArrayPluginConfig } from 'sanity-plugin-internationalized-array';\n\n/**\n * A localizable field type, passed through to\n * `sanity-plugin-internationalized-array`. Built-in shortcuts:\n * - `'string'` / `'text'` (or any Sanity type name) wrap that type.\n * - `'block'` wraps a Portable Text array (`array` of `block`).\n * - An object form supplies a field definition verbatim; the generated type is\n * named `internationalizedArray<Name>`.\n */\nexport type FieldLevelFieldType =\n | string\n | {\n /** Suffix used in the generated type name, e.g. `seo` β†’ `internationalizedArraySeo`. */\n name: string;\n /** Sanity type of the wrapped field (e.g. an object type name). */\n type: string;\n title?: string;\n of?: unknown[];\n fields?: unknown[];\n options?: Record<string, unknown>;\n };\n\n/**\n * Field-level localization options. `gtPlugin` forwards these to\n * `sanity-plugin-internationalized-array` β€” the reference Sanity plugin, which\n * gt-sanity configures rather than reimplements β€” keeping `sourceLocale` /\n * `locales` from `gtPlugin()` as the only source of locale identity.\n */\nexport type GTFieldLevelLocalizationConfig = {\n /** Register `internationalizedArray*` schema types + Studio UI. Default `false`. */\n enabled?: boolean;\n /** Which field types to wrap. Default `['string', 'text']`. */\n fieldTypes?: FieldLevelFieldType[];\n /** Per-locale display labels shown in the Studio input. */\n languageTitles?: Record<string, string>;\n /** Compute a display label for a locale (overrides `languageTitles`). */\n getLanguageTitle?: (locale: string) => string;\n /**\n * Locales pre-populated on empty localized fields.\n * Default: the plugin's source locale.\n */\n defaultLanguages?: string[];\n /** Passed through to `sanity-plugin-internationalized-array`. */\n apiVersion?: InternationalizedArrayPluginConfig['apiVersion'];\n /** Passed through to `sanity-plugin-internationalized-array`. */\n buttonLocations?: InternationalizedArrayPluginConfig['buttonLocations'];\n /** Passed through to `sanity-plugin-internationalized-array`. */\n buttonAddAll?: InternationalizedArrayPluginConfig['buttonAddAll'];\n /** Passed through to `sanity-plugin-internationalized-array`. */\n languageDisplay?: InternationalizedArrayPluginConfig['languageDisplay'];\n};\n\nexport type ResolvedFieldLevelConfig = Required<\n Pick<GTFieldLevelLocalizationConfig, 'enabled' | 'fieldTypes'>\n> &\n GTFieldLevelLocalizationConfig;\n\nexport function resolveFieldLevelConfig(\n config: GTFieldLevelLocalizationConfig | undefined\n): ResolvedFieldLevelConfig {\n return {\n enabled: false,\n fieldTypes: ['string', 'text'],\n ...config,\n };\n}\n\n/** Map a GT field-type shortcut to the native plugin's `fieldTypes` entry. */\nfunction toNativeFieldType(\n fieldType: FieldLevelFieldType\n): InternationalizedArrayPluginConfig['fieldTypes'][number] {\n if (fieldType === 'block') {\n return {\n name: 'block',\n type: 'array',\n of: [{ type: 'block' }],\n } as unknown as InternationalizedArrayPluginConfig['fieldTypes'][number];\n }\n return fieldType as InternationalizedArrayPluginConfig['fieldTypes'][number];\n}\n\n/**\n * Configure `sanity-plugin-internationalized-array` from gtPlugin locale\n * config. The native plugin owns the `internationalizedArray*` schema types\n * and the Studio UI; gt-sanity only reads and writes the stored\n * `{ _key, _type, language, value }` data during translation.\n */\nexport function buildInternationalizedArrayPlugin(\n config: ResolvedFieldLevelConfig,\n sourceLocale: string,\n locales: string[],\n customMapping?: CustomMapping\n): PluginOptions {\n const languageTitle = (locale: string) =>\n config.getLanguageTitle?.(locale) ??\n config.languageTitles?.[locale] ??\n formatLocalePropertiesLabel(\n locale,\n getLocaleProperties(locale, sourceLocale, customMapping),\n customMapping?.[locale]\n );\n\n const allLocales = Array.from(new Set([sourceLocale, ...locales]));\n\n return internationalizedArray({\n languages: allLocales.map((id) => ({ id, title: languageTitle(id) })),\n defaultLanguages: config.defaultLanguages ?? [sourceLocale],\n fieldTypes: config.fieldTypes.map(toNativeFieldType),\n ...(config.apiVersion !== undefined && { apiVersion: config.apiVersion }),\n ...(config.buttonLocations !== undefined && {\n buttonLocations: config.buttonLocations,\n }),\n ...(config.buttonAddAll !== undefined && {\n buttonAddAll: config.buttonAddAll,\n }),\n ...(config.languageDisplay !== undefined && {\n languageDisplay: config.languageDisplay,\n }),\n });\n}\n","import React from 'react';\nimport { Badge, Box, Card, Flex, Spinner, Stack, Text } from '@sanity/ui';\nimport { Preview, useSchema, type SanityDocument } from 'sanity';\nimport { useIntentLink } from 'sanity/router';\nimport { LanguageStatus } from '../shared/LanguageStatus';\nimport { resolveLanguageStatusState } from '../../utils/languageStatusState';\nimport { useTranslations } from '../TranslationsProvider';\nimport {\n createTranslationStatusKey,\n getDocumentPublishedId,\n} from '../../utils/documentIds';\n\nconst DocumentRow: React.FC<{ document: SanityDocument }> = ({ document }) => {\n const {\n locales,\n translationStatuses,\n pendingTranslations,\n importingTranslations,\n downloadStatus,\n importedTranslations,\n handleImportDocument,\n branchId,\n getVersionId,\n } = useTranslations();\n\n const schema = useSchema();\n const schemaType = schema.get(document._type);\n const publishedId = getDocumentPublishedId(document);\n\n const editLink = useIntentLink({\n intent: 'edit',\n params: { id: publishedId, type: document._type },\n });\n\n const enabledLocales = locales.filter((locale) => locale.enabled !== false);\n\n return (\n <Card border radius={3} overflow='hidden'>\n <Card\n as='a'\n href={editLink.href}\n onClick={editLink.onClick}\n padding={2}\n radius={0}\n borderBottom\n style={{ textDecoration: 'none', color: 'inherit' }}\n title='Open document'\n >\n <Flex align='center' gap={3}>\n <Box flex={1}>\n {schemaType ? (\n <Preview value={document} schemaType={schemaType} />\n ) : (\n <Text weight='semibold' size={1}>\n {publishedId}\n </Text>\n )}\n </Box>\n <Badge fontSize={0} radius={2}>\n {schemaType?.title ?? document._type}\n </Badge>\n </Flex>\n </Card>\n\n <Box paddingY={1}>\n {enabledLocales.length > 0 ? (\n <Stack gap={1}>\n {enabledLocales.map((locale) => {\n const versionId = getVersionId(document);\n const key = createTranslationStatusKey(\n branchId,\n publishedId,\n versionId,\n locale.localeId\n );\n const status = translationStatuses.get(key);\n const isDownloaded = downloadStatus.downloaded.has(key);\n const isImported = importedTranslations.has(key);\n\n return (\n <LanguageStatus\n key={`${document._id}-${versionId}-${locale.localeId}`}\n localeId={locale.localeId}\n state={resolveLanguageStatusState({\n status,\n isImported: isImported || isDownloaded,\n isPending: pendingTranslations.has(key),\n })}\n isImporting={importingTranslations.has(key)}\n importFile={async () => {\n await handleImportDocument(\n publishedId,\n versionId,\n locale.localeId\n );\n }}\n />\n );\n })}\n </Stack>\n ) : (\n <Box padding={3}>\n <Text size={1} muted>\n No locales configured\n </Text>\n </Box>\n )}\n </Box>\n </Card>\n );\n};\n\nexport const TranslationsTable: React.FC = () => {\n const { documents, loadingDocuments } = useTranslations();\n\n if (loadingDocuments) {\n return (\n <Flex align='center' justify='center' padding={4}>\n <Spinner />\n </Flex>\n );\n }\n\n return (\n <Box style={{ maxHeight: '60vh', overflowY: 'auto' }}>\n <Stack gap={2}>\n {documents.map((document) => (\n <DocumentRow key={document._id} document={document} />\n ))}\n </Stack>\n </Box>\n );\n};\n","import React, { useState } from 'react';\nimport {\n Box,\n Button,\n Card,\n Checkbox,\n Dialog,\n Flex,\n Stack,\n Text,\n} from '@sanity/ui';\nimport { useTranslations } from '../TranslationsProvider';\n\ninterface TranslateAllDialogProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport const TranslateAllDialog: React.FC<TranslateAllDialogProps> = ({\n isOpen,\n onClose,\n}) => {\n const { documents, handleTranslateAll } = useTranslations();\n const [force, setForce] = useState(false);\n\n const handleConfirm = async () => {\n onClose();\n setForce(false);\n await handleTranslateAll({ force });\n };\n\n const handleCancel = () => {\n setForce(false);\n onClose();\n };\n\n if (!isOpen) return null;\n\n return (\n <Dialog\n header='Confirm Translation'\n id='translate-all-dialog'\n onClose={handleCancel}\n footer={\n <Box padding={3}>\n <Flex gap={2}>\n <Button text='Cancel' mode='ghost' onClick={handleCancel} />\n <Button\n text={force ? 'Retranslate All' : 'Translate All'}\n tone={force ? 'caution' : 'default'}\n onClick={handleConfirm}\n />\n </Flex>\n </Box>\n }\n >\n <Box padding={4}>\n <Stack gap={4}>\n <Stack gap={3}>\n <Text>\n Are you sure you want to create translations for all{' '}\n {documents.length} documents?\n </Text>\n <Text size={1} muted>\n This will submit all documents to General Translation for\n processing.\n </Text>\n </Stack>\n\n <Card\n padding={3}\n radius={2}\n tone={force ? 'caution' : 'transparent'}\n border\n >\n <Flex align='flex-start' gap={3}>\n <Checkbox\n id='translate-all-force'\n checked={force}\n onChange={(event: React.ChangeEvent<HTMLInputElement>) =>\n setForce(event.currentTarget.checked)\n }\n />\n <Stack gap={2} flex={1}>\n <Text size={1} weight='medium'>\n <label htmlFor='translate-all-force'>\n Retranslate from scratch\n </label>\n </Text>\n <Text size={1} muted>\n {force\n ? 'Existing translations will be discarded and regenerated. Edits made to translated documents will be lost.'\n : 'Leave unchecked to reuse existing translations, including edits made to translated documents in the Studio.'}\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","import React from 'react';\nimport { Box, Button, Dialog, Flex, Stack, Text } from '@sanity/ui';\nimport { useTranslations } from '../TranslationsProvider';\n\ninterface ImportAllDialogProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport const ImportAllDialog: React.FC<ImportAllDialogProps> = ({\n isOpen,\n onClose,\n}) => {\n const { documents, handleImportAll } = useTranslations();\n\n const handleConfirm = async () => {\n onClose();\n await handleImportAll();\n };\n\n if (!isOpen) return null;\n\n return (\n <Dialog\n header='Confirm Import'\n id='import-all-dialog'\n onClose={onClose}\n footer={\n <Box padding={3}>\n <Flex gap={2}>\n <Button text='Cancel' mode='ghost' onClick={onClose} />\n <Button text='Import All' tone='caution' onClick={handleConfirm} />\n </Flex>\n </Box>\n }\n >\n <Box padding={4}>\n <Stack gap={3}>\n <Text>\n Are you sure you want to import translations for all{' '}\n {documents.length} documents?\n </Text>\n <Text size={1} muted>\n This will download and apply translated content to your documents.\n Note that this will overwrite any existing translations!\n </Text>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","import React from 'react';\nimport { Box, Button, Dialog, Flex, Stack, Text } from '@sanity/ui';\nimport { useTranslations } from '../TranslationsProvider';\n\ninterface ImportMissingDialogProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport const ImportMissingDialog: React.FC<ImportMissingDialogProps> = ({\n isOpen,\n onClose,\n}) => {\n const { handleImportMissing } = useTranslations();\n\n const handleConfirm = async () => {\n onClose();\n await handleImportMissing();\n };\n\n if (!isOpen) return null;\n\n return (\n <Dialog\n header='Confirm Import Missing'\n id='import-missing-dialog'\n onClose={onClose}\n footer={\n <Box padding={3}>\n <Flex gap={2}>\n <Button text='Cancel' mode='ghost' onClick={onClose} />\n <Button text='Import Missing' onClick={handleConfirm} />\n </Flex>\n </Box>\n }\n >\n <Box padding={4}>\n <Stack gap={3}>\n <Text>\n Import only the missing translations (translations that are ready\n but haven't been imported to Sanity yet)?\n </Text>\n <Text size={1} muted>\n This will check existing translation metadata and only import\n translations that don't already exist in your dataset.\n </Text>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","import React from 'react';\nimport { Box, Button, Dialog, Flex, Stack, Text } from '@sanity/ui';\nimport { useTranslations } from '../TranslationsProvider';\n\ninterface UploadExistingDialogProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport const UploadExistingDialog: React.FC<UploadExistingDialogProps> = ({\n isOpen,\n onClose,\n}) => {\n const { documents, handleUploadExistingTranslations } = useTranslations();\n\n const handleConfirm = async () => {\n onClose();\n await handleUploadExistingTranslations();\n };\n\n if (!isOpen) return null;\n\n return (\n <Dialog\n header='Save local edits'\n id='upload-existing-dialog'\n onClose={onClose}\n footer={\n <Box padding={3}>\n <Flex gap={2}>\n <Button text='Cancel' mode='ghost' onClick={onClose} />\n <Button text='Save Local Edits' onClick={handleConfirm} />\n </Flex>\n </Box>\n }\n >\n <Box padding={4}>\n <Stack gap={3}>\n <Text>\n Save the translations currently in Sanity for all {documents.length}{' '}\n documents to General Translation?\n </Text>\n <Text size={1} muted>\n They become the stored translation for each locale, so later\n translation runs reuse them. Anything General Translation already\n holds for those versions is replaced. No translation is started.\n </Text>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","import React from 'react';\nimport { Flex, Text, Spinner } from '@sanity/ui';\n\ninterface BatchProgressProps {\n isActive: boolean;\n current: number;\n total: number;\n operationName: string;\n}\n\nexport const BatchProgress: React.FC<BatchProgressProps> = ({\n isActive,\n current,\n total,\n operationName,\n}) => {\n if (!isActive) return null;\n\n return (\n <Flex justify='center' align='center' gap={3}>\n <Spinner size={1} />\n <Text size={1}>\n {operationName} {current} of {total}...\n </Text>\n </Flex>\n );\n};\n","import React, { useState } from 'react';\nimport {\n Badge,\n Box,\n Button,\n Card,\n Container,\n Flex,\n Heading,\n Stack,\n Switch,\n Text,\n} from '@sanity/ui';\nimport { Tooltip } from '@sanity/ui/tooltip';\nimport { CheckmarkCircleIcon } from '@sanity/icons/CheckmarkCircle';\nimport { DownloadIcon } from '@sanity/icons/Download';\nimport { LinkIcon } from '@sanity/icons/Link';\nimport { PublishIcon } from '@sanity/icons/Publish';\nimport { RefreshIcon } from '@sanity/icons/Refresh';\nimport { TranslateIcon } from '@sanity/icons/Translate';\nimport { UploadIcon } from '@sanity/icons/Upload';\nimport { Link } from 'sanity/router';\nimport { BaseTranslationWrapper } from '../shared/BaseTranslationWrapper';\nimport { TranslationsProvider, useTranslations } from '../TranslationsProvider';\nimport { TranslationsTable } from './TranslationsTable';\nimport { TranslateAllDialog } from './TranslateAllDialog';\nimport { ImportAllDialog } from './ImportAllDialog';\nimport { ImportMissingDialog } from './ImportMissingDialog';\nimport { UploadExistingDialog } from './UploadExistingDialog';\nimport { SaveLocalTranslationsDialog } from './SaveLocalTranslationsDialog';\nimport { DebugInfoDialog } from './DebugInfoDialog';\nimport { BatchProgress } from './BatchProgress';\nimport { version as PACKAGE_VERSION } from '../../../package.json';\n\nconst TranslationsToolContent: React.FC = () => {\n const [isTranslateAllDialogOpen, setIsTranslateAllDialogOpen] =\n useState(false);\n const [isImportAllDialogOpen, setIsImportAllDialogOpen] = useState(false);\n const [isImportMissingDialogOpen, setIsImportMissingDialogOpen] =\n useState(false);\n const [isUploadExistingDialogOpen, setIsUploadExistingDialogOpen] =\n useState(false);\n const [isSaveLocalDialogOpen, setIsSaveLocalDialogOpen] = useState(false);\n const [isDebugInfoDialogOpen, setIsDebugInfoDialogOpen] = useState(false);\n\n const {\n isBusy,\n documents,\n locales,\n autoRefresh,\n loadingDocuments,\n importProgress,\n importedTranslations,\n pendingTranslations,\n isRefreshing,\n setAutoRefresh,\n preserveExistingTranslations,\n setPreserveExistingTranslations,\n handleRefreshAll,\n handlePatchDocumentReferences,\n handlePublishAllTranslations,\n } = useTranslations();\n\n // Track which specific operation is running\n const [currentOperation, setCurrentOperation] = useState<string | null>(null);\n\n const getProgressOperationName = () => {\n switch (currentOperation) {\n case 'Import All':\n return 'Importing';\n case 'Import Missing':\n return 'Importing missing';\n case 'Save Local Edits':\n return 'Uploading existing';\n case 'Patch References':\n return 'Patching';\n case 'Publish Translations':\n return 'Publishing';\n default:\n return 'Processing';\n }\n };\n\n // Reset current operation when operation completes\n React.useEffect(() => {\n if (!isBusy && !importProgress.isImporting) {\n setCurrentOperation(null);\n }\n }, [isBusy, importProgress.isImporting]);\n\n // A translation run stays in flight after the request resolves, so `isBusy`\n // alone drops the button back to idle while work is still happening. The\n // per-locale rows already read \"Translating…\"; this keeps the top-level\n // button honest and guards against enqueueing the same run twice.\n const isWaitingOnTranslations = pendingTranslations.size > 0;\n\n const enabledLocaleCount = locales.filter((l) => l.enabled !== false).length;\n const totalTranslations = documents.length * enabledLocaleCount;\n const actionsDisabled = isBusy || loadingDocuments || documents.length === 0;\n\n return (\n <Container width={2}>\n <Box padding={4} marginTop={5}>\n <Stack gap={5}>\n <Flex align='flex-start' justify='space-between' gap={4}>\n <Stack gap={3}>\n <Heading as='h2' size={3}>\n Translations\n </Heading>\n <Text size={1} muted>\n Manage your document translations from this centralized\n location.\n </Text>\n </Stack>\n\n <Button\n icon={TranslateIcon}\n text={isWaitingOnTranslations ? 'Translating…' : 'Translate All'}\n loading={\n (isBusy && currentOperation === 'Translate All') ||\n isWaitingOnTranslations\n }\n onClick={() => {\n setCurrentOperation('Translate All');\n setIsTranslateAllDialogOpen(true);\n }}\n disabled={actionsDisabled || isWaitingOnTranslations}\n />\n </Flex>\n\n <Stack gap={3}>\n <Flex align='center' justify='space-between' gap={3}>\n <Text size={1} muted>\n {loadingDocuments\n ? 'Loading documents...'\n : `${documents.length} ${\n documents.length === 1 ? 'document' : 'documents'\n } available for translation`}\n </Text>\n\n <Flex gap={3} align='center'>\n <Flex gap={2} align='center'>\n <Text size={1} muted>\n Save local edits\n </Text>\n <Switch\n checked={preserveExistingTranslations}\n onChange={() => {\n // Turning it on changes what wins on a conflict, so\n // explain before enabling; turning it off is safe.\n if (preserveExistingTranslations) {\n setPreserveExistingTranslations(false);\n } else {\n setIsSaveLocalDialogOpen(true);\n }\n }}\n />\n </Flex>\n <Flex gap={2} align='center'>\n <Text size={1} muted>\n Auto-refresh\n </Text>\n <Switch\n checked={autoRefresh}\n onChange={() => setAutoRefresh(!autoRefresh)}\n />\n </Flex>\n <Button\n fontSize={1}\n padding={2}\n mode='ghost'\n icon={RefreshIcon}\n text='Refresh'\n loading={isRefreshing}\n onClick={() => handleRefreshAll()}\n disabled={isRefreshing || actionsDisabled}\n />\n </Flex>\n </Flex>\n\n <TranslationsTable />\n </Stack>\n\n <Stack gap={3}>\n <Flex gap={2} align='center' justify='space-between'>\n <Flex gap={2} align='center' wrap='wrap'>\n <Tooltip\n placement='top'\n content='Imports and overrides all translations'\n >\n <Button\n mode='ghost'\n fontSize={1}\n onClick={() => {\n setCurrentOperation('Import All');\n setIsImportAllDialogOpen(true);\n }}\n text='Import All'\n loading={isBusy && currentOperation === 'Import All'}\n icon={DownloadIcon}\n disabled={actionsDisabled}\n />\n </Tooltip>\n <Tooltip\n placement='top'\n content=\"Imports all translations that are not yet imported (according to the source document's translation.metadata document)\"\n >\n <Button\n mode='ghost'\n fontSize={1}\n onClick={() => {\n setCurrentOperation('Import Missing');\n setIsImportMissingDialogOpen(true);\n }}\n text='Import Missing'\n loading={isBusy && currentOperation === 'Import Missing'}\n icon={DownloadIcon}\n disabled={actionsDisabled}\n />\n </Tooltip>\n <Tooltip\n placement='top'\n content='Uploads the translations already in Sanity to General Translation, preserving human edits'\n >\n <Button\n mode='ghost'\n fontSize={1}\n onClick={() => {\n setCurrentOperation('Save Local Edits');\n setIsUploadExistingDialogOpen(true);\n }}\n text='Save Local Edits'\n loading={isBusy && currentOperation === 'Save Local Edits'}\n icon={UploadIcon}\n disabled={actionsDisabled}\n />\n </Tooltip>\n <Tooltip\n placement='top'\n content='Replaces references in documents with the corresponding translated document reference'\n >\n <Button\n mode='ghost'\n fontSize={1}\n onClick={() => {\n setCurrentOperation('Patch References');\n handlePatchDocumentReferences();\n }}\n text='Patch References'\n loading={isBusy && currentOperation === 'Patch References'}\n icon={LinkIcon}\n disabled={actionsDisabled}\n />\n </Tooltip>\n <Tooltip\n placement='top'\n content='Publishes all translations whose source document is published'\n >\n <Button\n mode='ghost'\n fontSize={1}\n onClick={() => {\n setCurrentOperation('Publish Translations');\n handlePublishAllTranslations();\n }}\n text='Publish Translations'\n loading={\n isBusy && currentOperation === 'Publish Translations'\n }\n icon={PublishIcon}\n disabled={actionsDisabled}\n />\n </Tooltip>\n </Flex>\n\n {totalTranslations > 0 &&\n importedTranslations.size === totalTranslations && (\n <Badge tone='positive' fontSize={0} radius={2}>\n <Flex align='center' gap={1}>\n <CheckmarkCircleIcon />\n <Box>All translations imported</Box>\n </Flex>\n </Badge>\n )}\n {importedTranslations.size > 0 &&\n importedTranslations.size < totalTranslations && (\n <Text size={1} muted>\n {importedTranslations.size}/{totalTranslations} imported\n </Text>\n )}\n </Flex>\n\n <BatchProgress\n isActive={importProgress.isImporting}\n current={importProgress.current}\n total={importProgress.total}\n operationName={getProgressOperationName()}\n />\n </Stack>\n\n <Card borderTop paddingTop={4}>\n <Flex align='center' justify='space-between' gap={3} wrap='wrap'>\n <Text size={1} muted>\n For more information, see the{' '}\n <Link href='https://dash.generaltranslation.com'>\n General Translation Dashboard\n </Link>\n .\n </Text>\n <Flex align='center' gap={2}>\n <Text size={1} muted>\n gt-sanity v{PACKAGE_VERSION}\n </Text>\n <Button\n fontSize={1}\n padding={2}\n mode='bleed'\n text='Debug info'\n onClick={() => setIsDebugInfoDialogOpen(true)}\n />\n </Flex>\n </Flex>\n </Card>\n </Stack>\n </Box>\n\n <TranslateAllDialog\n isOpen={isTranslateAllDialogOpen}\n onClose={() => setIsTranslateAllDialogOpen(false)}\n />\n <ImportAllDialog\n isOpen={isImportAllDialogOpen}\n onClose={() => setIsImportAllDialogOpen(false)}\n />\n <ImportMissingDialog\n isOpen={isImportMissingDialogOpen}\n onClose={() => setIsImportMissingDialogOpen(false)}\n />\n <SaveLocalTranslationsDialog\n isOpen={isSaveLocalDialogOpen}\n onClose={() => setIsSaveLocalDialogOpen(false)}\n onConfirm={() => {\n setPreserveExistingTranslations(true);\n setIsSaveLocalDialogOpen(false);\n }}\n />\n <UploadExistingDialog\n isOpen={isUploadExistingDialogOpen}\n onClose={() => setIsUploadExistingDialogOpen(false)}\n />\n <DebugInfoDialog\n isOpen={isDebugInfoDialogOpen}\n onClose={() => setIsDebugInfoDialogOpen(false)}\n />\n </Container>\n );\n};\n\nconst TranslationsTool: React.FC = () => {\n return (\n <BaseTranslationWrapper showContainer={false}>\n <TranslationsProvider>\n <TranslationsToolContent />\n </TranslationsProvider>\n </BaseTranslationWrapper>\n );\n};\n\nexport default TranslationsTool;\n","/**\n * `locales` is the list of translation *targets*, but configs often repeat the\n * source locale there β€” spreading `gt.config.json`, which pairs `defaultLocale`\n * with a `locales` array, is the common way to end up with it.\n *\n * A repeated locale is not cosmetic: it reaches\n * `@sanity/document-internationalization` as a duplicate `supportedLanguages`\n * entry, and `sanity-plugin-internationalized-array` then resolves every\n * language after the duplicate to the wrong array index. Its reorder effect\n * rewrites the array, re-renders, and re-flags the same mismatch forever, which\n * crashes the Studio with \"Maximum update depth exceeded\".\n */\nexport function resolveTargetLocales(\n sourceLocale: string,\n locales: string[] | undefined\n): string[] {\n return Array.from(new Set(locales)).filter(\n (locale) => locale !== sourceLocale\n );\n}\n","import { getLocaleProperties } from 'generaltranslation';\nimport { createDiagnosticMessage } from 'generaltranslation/internal';\nimport type {\n ListItemBuilder,\n StructureBuilder,\n StructureResolver,\n StructureResolverContext,\n} from 'sanity/structure';\nimport { pluginConfig } from '../adapter/core';\nimport { formatLocalePropertiesLabel } from '../utils/localeDisplay';\nimport { SANITY_API_VERSION } from '../utils/shared';\n\nexport type GTStructureOptions = {\n /**\n * Document types to group by locale. Defaults to the types in\n * `translateDocuments` that are translated into per-locale documents.\n */\n types?: string[];\n /** Title of the pane holding the source-locale documents. */\n sourceTitle?: string;\n /** Title of a locale's pane. Defaults to `<Type> in <Locale>`. */\n localeTitle?: (typeTitle: string, locale: string, label: string) => string;\n};\n\n/**\n * Document types translated into per-locale documents.\n *\n * Types localized through internationalized arrays are excluded: their\n * translations live inside the source document, so there is no per-locale\n * document to group.\n */\nfunction documentLevelTypes(): string[] {\n const level = pluginConfig.getTranslationLevel();\n const types = pluginConfig\n .getTranslateDocuments()\n .map((filter) => filter.type)\n .filter((type): type is string => Boolean(type));\n\n if (level === 'internationalizedArray') return [];\n if (level === 'mixed') {\n const fieldLevel = new Set(\n pluginConfig.getFieldLevelDocuments().map((filter) => filter.type)\n );\n return types.filter((type) => !fieldLevel.has(type));\n }\n return types;\n}\n\nfunction localeLabel(locale: string): string {\n const sourceLocale = pluginConfig.getSourceLocale();\n return formatLocalePropertiesLabel(\n locale,\n getLocaleProperties(locale, sourceLocale)\n );\n}\n\nfunction typeTitle(type: string, context?: StructureResolverContext): string {\n const schemaType = context?.schema?.get(type);\n return (schemaType?.title as string | undefined) ?? type;\n}\n\n/**\n * Builds one list item per translatable document type. Each expands into a\n * pane per locale, so translations are browsed by language instead of sitting\n * alongside their source in a single flat list.\n *\n * Returns an empty array when `translateDocuments` names no types, since the\n * grouping is per type.\n */\nexport function gtStructureItems(\n S: StructureBuilder,\n context?: StructureResolverContext,\n options: GTStructureOptions = {}\n): ListItemBuilder[] {\n const types = options.types ?? documentLevelTypes();\n\n if (types.length === 0) {\n console.warn(\n createDiagnosticMessage({\n source: 'gt-sanity',\n severity: 'Warning',\n whatHappened: 'No document types to group by locale',\n why: 'the structure helper groups per document type, and none were resolved from the plugin configuration',\n fix: 'List the types in `translateDocuments`, or pass them to the structure helper as `types`',\n })\n );\n return [];\n }\n\n const sourceLocale = pluginConfig.getSourceLocale();\n const languageField = pluginConfig.getLanguageField();\n const targetLocales = pluginConfig.getLocales();\n const titleFor =\n options.localeTitle ??\n ((title: string, _locale: string, label: string) => `${title} in ${label}`);\n\n return types.map((type) => {\n const title = typeTitle(type, context);\n\n // A document with no language field is the source: the plugin only\n // stamps the field on translations it creates, and existing content\n // predates the plugin.\n const sourceFilter = `_type == $type && (!defined(${languageField}) || ${languageField} == $locale)`;\n const localeFilter = `_type == $type && ${languageField} == $locale`;\n\n return S.listItem()\n .id(`gt-${type}`)\n .title(title)\n .child(\n S.list()\n .id(`gt-${type}-locales`)\n .title(title)\n .items([\n S.listItem()\n .id(`gt-${type}-${sourceLocale}`)\n .title(options.sourceTitle ?? localeLabel(sourceLocale))\n .child(\n S.documentList()\n .id(`gt-${type}-${sourceLocale}-list`)\n .title(options.sourceTitle ?? localeLabel(sourceLocale))\n .schemaType(type)\n .apiVersion(SANITY_API_VERSION)\n .filter(sourceFilter)\n .params({ type, locale: sourceLocale })\n ),\n S.divider(),\n ...targetLocales.map((locale) => {\n const paneTitle = titleFor(title, locale, localeLabel(locale));\n return S.listItem()\n .id(`gt-${type}-${locale}`)\n .title(paneTitle)\n .child(\n S.documentList()\n .id(`gt-${type}-${locale}-list`)\n .title(paneTitle)\n .schemaType(type)\n .apiVersion(SANITY_API_VERSION)\n .filter(localeFilter)\n .params({ type, locale })\n );\n }),\n ])\n );\n });\n}\n\n/**\n * A ready-made structure that lists every translatable type grouped by locale.\n *\n * Use `gtStructureItems` instead to place these alongside other list items.\n */\nexport function gtStructure(\n options: GTStructureOptions = {}\n): StructureResolver {\n return (S, context) =>\n S.list()\n .title('Content')\n .items(gtStructureItems(S, context, options));\n}\n","import React from 'react';\nimport { SanityDocument } from 'sanity';\nimport { BaseTranslationWrapper } from '../shared/BaseTranslationWrapper';\nimport { TranslationsProvider } from '../TranslationsProvider';\nimport { TranslationView } from './TranslationView';\n\ntype TranslationTabProps = {\n document: {\n displayed: SanityDocument;\n };\n};\n\nconst TranslationTab = (props: TranslationTabProps) => {\n const { displayed } = props.document;\n\n return (\n <BaseTranslationWrapper showContainer={false}>\n <TranslationsProvider singleDocument={displayed}>\n <TranslationView />\n </TranslationsProvider>\n </BaseTranslationWrapper>\n );\n};\n\nexport default TranslationTab;\n","import type { PortableTextHtmlComponents } from '@portabletext/to-html';\nimport { getLocaleProperties } from 'generaltranslation';\nimport {\n createDiagnosticMessage,\n libraryDefaultLocale,\n} from 'generaltranslation/internal';\nimport { formatLocalePropertiesLabel } from './utils/localeDisplay';\nimport { definePlugin } from 'sanity';\nimport { route } from 'sanity/router';\nimport { translateAction } from './actions/translateAction';\nimport {\n DEFAULT_TRANSLATION_PREFERENCES,\n gt,\n pluginConfig,\n} from './adapter/core';\nimport type {\n DedupeFields,\n IgnoreFields,\n SkipFields,\n TranslateDocumentFilter,\n FieldLevelTranslationMode,\n} from './adapter/types';\nimport {\n buildInternationalizedArrayPlugin,\n resolveFieldLevelConfig,\n} from './schema/fieldLevelConfig';\nimport type { GTFieldLevelLocalizationConfig } from './schema/fieldLevelConfig';\nimport './schema/schemaOptions';\nimport TranslationsTool from './components/page/TranslationsTool';\nimport { documentInternationalization } from './documentInternationalization';\nimport type { CustomDeserializers } from './serialization/types';\nimport { resolveTargetLocales } from './utils/locales';\nimport { SECRETS_NAMESPACE } from './utils/shared';\n\n// ===== Document Internationalization ===== //\nexport {\n useDocumentInternationalizationContext,\n DocumentInternationalizationMenu,\n useDeleteTranslationAction,\n useDuplicateWithTranslationsAction,\n} from './documentInternationalization';\nexport { documentInternationalization };\nexport type {\n DocumentInternationalizationConfig,\n Language,\n Metadata,\n TranslationReference,\n} from './documentInternationalization';\n\n// ===== Studio Structure ===== //\n// Grouping translations by locale is opt-in: the structure tool's layout is\n// owned by `structureTool({ structure })` in the Studio config, which a plugin\n// cannot set on the user's behalf.\nexport { gtStructure, gtStructureItems } from './structure/localizedStructure';\nexport type { GTStructureOptions } from './structure/localizedStructure';\n\n// ===== Serialization Helpers ===== //\nexport { default as TranslationsTab } from './components/tab/TranslationsTab';\nexport { findLatestDraft } from './configuration/utils/findLatestDraft';\nexport { BaseDocumentSerializer } from './serialization/serialize/index';\nexport { BaseDocumentDeserializer } from './serialization/deserialize/BaseDocumentDeserializer';\nexport { BaseDocumentMerger } from './serialization/BaseDocumentMerger';\nexport {\n defaultStopTypes,\n customSerializers,\n} from './serialization/BaseSerializationConfig';\nexport { attachGTData, detachGTData } from './serialization/data';\nexport { translateAction };\nexport type {\n Secrets,\n Adapter,\n ExportForTranslation,\n ImportTranslation,\n TranslationFunctionContext,\n TranslationsTabConfigOptions,\n} from './types';\nexport type { SerializedDocument } from './serialization/types';\n\n// ===== Field-Level (Internationalized Array) Localization ===== //\n// gt-sanity configures the reference plugin rather than shipping its own UI;\n// the plugin and its types are re-exported for direct/advanced use.\nexport {\n internationalizedArray,\n internationalizedArrayLanguageFilter,\n isInternationalizedArrayItemType,\n} from 'sanity-plugin-internationalized-array';\nexport type {\n PluginConfig as InternationalizedArrayPluginConfig,\n Language as InternationalizedArrayLanguage,\n} from 'sanity-plugin-internationalized-array';\nexport type {\n GTFieldLevelLocalizationConfig,\n FieldLevelFieldType,\n} from './schema/fieldLevelConfig';\nexport type { GTSchemaFieldOptions } from './schema/schemaOptions';\nexport type { FieldLevelTranslationMode };\n\nexport type GTPluginConfig = Omit<\n Parameters<typeof gt.setConfig>[0],\n 'locales'\n> & {\n locales: string[];\n // Alias for sourceLocale β€” accepted so users can spread gt.config.json directly.\n defaultLocale?: string;\n singletons?: string[];\n // Optional mapping function to map source document ids to translated singleton document ids\n // By default, the translated singleton document is is `${sourceDocumentId}-${locale}`\n singletonMapping?: (sourceDocumentId: string, locale: string) => string;\n ignoreFields?: IgnoreFields[];\n dedupeFields?: DedupeFields[];\n skipFields?: SkipFields[];\n languageField?: string;\n translateDocuments?: TranslateDocumentFilter[] | string[];\n secretsNamespace?: string;\n additionalStopTypes?: string[];\n additionalSerializers?: Partial<PortableTextHtmlComponents>;\n additionalDeserializers?: CustomDeserializers;\n additionalBlockDeserializers?: unknown[];\n // When true (default), automatically adds the @sanity/document-internationalization plugin\n // with language badges, translation menu, and per-language templates.\n // Requires translateDocuments to specify which document types to enable translations for.\n showDocumentInternationalization?: boolean;\n // Field-level (internationalized-array) localization. When enabled,\n // auto-configures sanity-plugin-internationalized-array (the reference\n // plugin, which owns the schema types and Studio UI) from this plugin's\n // locales. Leave disabled if you register that plugin yourself.\n // `fieldLevelLocalization` is a descriptive alias for the same config.\n internationalizedArray?: GTFieldLevelLocalizationConfig;\n fieldLevelLocalization?: GTFieldLevelLocalizationConfig;\n // How matched documents are translated. Independent from schema setup:\n // enabling `internationalizedArray` only adds editable fields; routing\n // translation through the array path requires opting in here. Default 'document'.\n translationLevel?: FieldLevelTranslationMode;\n // In 'mixed' mode, the document types that use the internationalized-array\n // strategy; everything else stays document-level.\n fieldLevelDocuments?: TranslateDocumentFilter[] | string[];\n // Sets the initial state of the \"Local translations win\" toggle. When on,\n // the translations currently in Sanity are uploaded to General Translation\n // before a translation run, so they become the baseline the next translation\n // reuses. Local content overwrites whatever General Translation holds for\n // that source version, including a completed translation that has not been\n // imported yet. Off by default; the toggle can be flipped per session.\n preserveExistingTranslations?: boolean;\n // Starting state of the automatic actions in the translations UI. These are\n // defaults, not locks: a change the user makes in the Studio is remembered in\n // localStorage (per project and dataset) and preferred on their next visit.\n // Defaults to true.\n autoRefresh?: boolean;\n // Import a translation as soon as it completes. Defaults to true.\n autoImport?: boolean;\n // Repoint references to their translated counterparts after import. Defaults\n // to FALSE β€” when a translated document has already been published and has no\n // draft, the rewrite is applied to a draft seeded from it, so this edits\n // documents you may consider finished.\n autoPatchReferences?: boolean;\n // Publish translated documents after import. Defaults to FALSE β€” publishing\n // is the one automatic action that puts content in front of readers and\n // cannot be undone by turning the switch back off.\n autoPublish?: boolean;\n};\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import {defineConfig} from 'sanity'\n * import {gtPlugin} from 'gt-sanity'\n *\n * export default defineConfig({\n * // ...\n * plugins: [gtPlugin()],\n * })\n * ```\n */\nexport const gtPlugin = definePlugin<GTPluginConfig>(\n ({\n languageField = 'language',\n sourceLocale,\n defaultLocale,\n locales,\n customMapping,\n apiKey,\n projectId,\n singletons,\n singletonMapping,\n ignoreFields,\n dedupeFields,\n skipFields,\n translateDocuments,\n secretsNamespace = SECRETS_NAMESPACE,\n additionalStopTypes = [],\n additionalSerializers = {},\n additionalDeserializers = {},\n additionalBlockDeserializers = [],\n showDocumentInternationalization = true,\n internationalizedArray,\n fieldLevelLocalization,\n translationLevel = 'document',\n fieldLevelDocuments,\n preserveExistingTranslations = DEFAULT_TRANSLATION_PREFERENCES.preserveExistingTranslations,\n autoRefresh = DEFAULT_TRANSLATION_PREFERENCES.autoRefresh,\n autoImport = DEFAULT_TRANSLATION_PREFERENCES.autoImport,\n autoPatchReferences = DEFAULT_TRANSLATION_PREFERENCES.autoPatchReferences,\n autoPublish = DEFAULT_TRANSLATION_PREFERENCES.autoPublish,\n }) => {\n // Resolve sourceLocale: explicit sourceLocale > defaultLocale (from gt.config.json) > library default\n const resolvedSourceLocale =\n sourceLocale ?? defaultLocale ?? libraryDefaultLocale;\n\n // `locales` holds translation targets only. Drop duplicates and the source\n // locale before anything downstream sees them β€” a repeated locale reaches\n // the Studio as a duplicate language and breaks the translations UI.\n const targetLocales = resolveTargetLocales(resolvedSourceLocale, locales);\n\n // Normalize translateDocuments: string[] β†’ TranslateDocumentFilter[]\n const normalizeFilters = (\n entries: (TranslateDocumentFilter | string)[] | undefined\n ): TranslateDocumentFilter[] | undefined =>\n entries\n ?.map((entry) => (typeof entry === 'string' ? { type: entry } : entry))\n .filter((filter) => filter.documentId || filter.type);\n\n const normalizedTranslateDocuments = normalizeFilters(translateDocuments);\n const normalizedFieldLevelDocuments =\n normalizeFilters(fieldLevelDocuments) ?? [];\n\n // `internationalizedArray` and `fieldLevelLocalization` are aliases.\n const rawFieldLevelConfig =\n internationalizedArray ?? fieldLevelLocalization;\n warnOnRemovedFieldLevelOptions(rawFieldLevelConfig);\n const fieldLevelConfig = resolveFieldLevelConfig(rawFieldLevelConfig);\n\n pluginConfig.init(\n secretsNamespace,\n languageField,\n resolvedSourceLocale,\n targetLocales,\n singletons || [],\n // singletons is a string array of singleton document ids\n singletonMapping ||\n ((sourceDocumentId, locale) => `${sourceDocumentId}-${locale}`),\n ignoreFields || [],\n dedupeFields || [],\n skipFields || [],\n normalizedTranslateDocuments || [],\n additionalStopTypes,\n additionalSerializers,\n additionalDeserializers,\n additionalBlockDeserializers,\n translationLevel,\n normalizedFieldLevelDocuments,\n {\n autoRefresh,\n autoImport,\n autoPatchReferences,\n autoPublish,\n preserveExistingTranslations,\n }\n );\n gt.setConfig({\n sourceLocale: resolvedSourceLocale,\n customMapping: customMapping,\n apiKey: apiKey,\n projectId: projectId,\n });\n\n // Document types localized in place via internationalized arrays must NOT\n // get @sanity/document-internationalization (language badges + per-locale\n // documents). Build the set of array-localized types from translationLevel.\n const arrayLocalizedTypes = new Set<string>();\n if (translationLevel === 'internationalizedArray') {\n normalizedTranslateDocuments\n ?.map((filter) => filter.type)\n .filter((type): type is string => !!type)\n .forEach((type) => arrayLocalizedTypes.add(type));\n } else if (translationLevel === 'mixed') {\n normalizedFieldLevelDocuments\n .map((filter) => filter.type)\n .filter((type): type is string => !!type)\n .forEach((type) => arrayLocalizedTypes.add(type));\n }\n\n // Auto-add document internationalization plugin\n const plugins = [];\n if (showDocumentInternationalization) {\n const schemaTypes =\n normalizedTranslateDocuments\n ?.map((filter) => filter.type)\n .filter((type): type is string => !!type)\n .filter((type) => !arrayLocalizedTypes.has(type)) ?? [];\n if (schemaTypes.length > 0) {\n const allLocales = [resolvedSourceLocale, ...targetLocales];\n const supportedLanguages = allLocales.map((locale) => {\n const props = getLocaleProperties(\n locale,\n resolvedSourceLocale,\n customMapping\n );\n return {\n id: locale,\n title: formatLocalePropertiesLabel(\n locale,\n props,\n customMapping?.[locale]\n ),\n };\n });\n plugins.push(\n documentInternationalization({\n supportedLanguages,\n schemaTypes,\n languageField,\n })\n );\n }\n }\n\n // Field-level localization is provided by the reference plugin,\n // configured from gtPlugin's locales. Users who already register\n // sanity-plugin-internationalized-array themselves should leave this\n // disabled β€” translation only reads the stored data shape.\n if (fieldLevelConfig.enabled) {\n plugins.push(\n buildInternationalizedArrayPlugin(\n fieldLevelConfig,\n resolvedSourceLocale,\n targetLocales,\n customMapping\n )\n );\n }\n\n return {\n name: 'gt-sanity',\n plugins,\n tools: [\n {\n name: 'translations',\n title: 'Translations',\n component: TranslationsTool,\n router: route.create('/*'),\n },\n ],\n document: {\n actions: (prev) => {\n return [...prev, translateAction];\n },\n },\n };\n }\n);\n\n// Options that existed while gt-sanity shipped its own field-level UI (v2.1.x)\n// and have no equivalent in sanity-plugin-internationalized-array.\nconst REMOVED_FIELD_LEVEL_OPTIONS = [\n 'typePrefix',\n 'includeCompatibilityTypes',\n 'components',\n] as const;\n\nfunction warnOnRemovedFieldLevelOptions(\n config: GTFieldLevelLocalizationConfig | undefined\n): void {\n if (!config) return;\n const removed = REMOVED_FIELD_LEVEL_OPTIONS.filter(\n (key) => (config as Record<string, unknown>)[key] !== undefined\n );\n if (removed.length === 0) return;\n console.warn(\n createDiagnosticMessage({\n source: 'gt-sanity',\n severity: 'Warning',\n whatHappened: `Ignored unsupported field-level localization ${removed.length === 1 ? 'option' : 'options'}`,\n why: 'field-level localization is now provided by sanity-plugin-internationalized-array, which has no equivalent for these options',\n fix: 'Remove them from the gtPlugin configuration',\n details: removed,\n })\n );\n}\n"],"names":["uploadTranslations","decodeBase64","awaitApiJobs","useSanityClient","client","isRecord","document","deserializeDocument","META_FIELDS","isPlainRecord","branchId","existingTranslations","secrets","PACKAGE_VERSION","customMapping","internationalizedArray"],"mappings":"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"}