sanity-plugin-transifex
5.1.215.1.22
~
Modified (2 files)
Index: package/package.json
===================================================================
--- package/package.json
+++ package/package.json
@@ -1,7 +1,7 @@
{
"name": "sanity-plugin-transifex",
- "version": "5.1.21",
+ "version": "5.1.22",
"description": "This plugin provides an in-studio integration with Transifex. It allows your editors to send any document to Transifex with the click of a button, monitor ongoing translations, and import partial or complete translations back into the studio.",
"keywords": [
"sanity",
"sanity-plugin"
@@ -26,19 +26,19 @@
".": "./dist/index.js",
"./package.json": "./package.json"
},
"dependencies": {
- "sanity-translations-tab": "^6.1.21"
+ "sanity-translations-tab": "^6.1.22"
},
"devDependencies": {
"@sanity/tsconfig": "^2.2.1",
- "@sanity/tsdown-config": "^0.26.0",
- "@types/react": "^19.2.18",
- "@types/react-dom": "^19.2.4",
- "oxc-transform-react": "^0.145.0",
- "react": "^19.2.8",
- "react-dom": "^19.2.8",
- "sanity": "^6.10.1",
+ "@sanity/tsdown-config": "^0.27.1",
+ "@types/react": "^19.3.0",
+ "@types/react-dom": "^19.3.0",
+ "oxc-transform-react": "^0.147.0",
+ "react": "^19.3.0",
+ "react-dom": "^19.3.0",
+ "sanity": "^6.16.0",
"styled-components": "^6.5.3",
"tsdown": "^0.22.14"
},
"peerDependencies": { Index: package/dist/index.js.map
===================================================================
--- package/dist/index.js.map
+++ package/dist/index.js.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"index.js","names":[],"sources":["../src/transifexAdapter/helpers.ts","../src/transifexAdapter/getLocales.ts","../src/transifexAdapter/getTranslationTask.ts","../src/transifexAdapter/createTask.ts","../src/transifexAdapter/getTranslation.ts","../src/transifexAdapter/index.ts","../src/index.ts"],"sourcesContent":["import type {Secrets} from 'sanity-translations-tab'\n\nexport const baseTransifexUrl = 'https://rest.api.transifex.com'\n\nexport const getHeaders = (secrets: Secrets | null): Record<string, string> => ({\n 'Authorization': `Bearer ${secrets?.token}`,\n 'Content-Type': 'application/vnd.api+json',\n})\n\nexport const projOrgSlug = (secrets: Secrets | null): string =>\n `o:${secrets?.organization}:p:${secrets?.project}`\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {baseTransifexUrl, projOrgSlug, getHeaders} from './helpers'\n\nexport const getLocales: Adapter['getLocales'] = async (secrets: Secrets | null) => {\n let locales = []\n if (secrets) {\n const response = await fetch(`${baseTransifexUrl}/projects/${projOrgSlug(secrets)}/languages`, {\n headers: getHeaders(secrets),\n })\n\n if (!response.ok) {\n throw Error(`Failed to retrieve locales from Transifex. Status: ${response.status}`)\n }\n\n locales = await response.json().then((res) =>\n res.data.map((lang: Record<string, any>) => ({\n enabled: true,\n description: lang['attributes']['name'],\n localeId: lang['attributes']['code'],\n })),\n )\n }\n return locales\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {getLocales} from './getLocales'\nimport {baseTransifexUrl, projOrgSlug, getHeaders} from './helpers'\n\nexport const getTranslationTask: Adapter['getTranslationTask'] = async (\n documentId: string,\n secrets: Secrets | null,\n) => {\n if (!documentId || !secrets) {\n return {\n taskId: documentId,\n documentId: documentId,\n locales: [],\n }\n }\n const projectFilter = `filter[project]=${projOrgSlug(secrets)}`\n const resourceFilter = `filter[resource]=${projOrgSlug(secrets)}:r:${documentId}`\n const task = await fetch(\n `${baseTransifexUrl}/resource_language_stats?${projectFilter}&${resourceFilter}`,\n {headers: getHeaders(secrets)},\n )\n .then((res) => {\n if (res.ok) {\n return res.json()\n }\n //normal -- just means that this task doesn't exist yet.\n else if (res.status === 404) {\n return {data: []}\n }\n throw Error(`Failed to retrieve tasks from Transifex. Status: ${res.status}`)\n })\n .then((res) => ({\n taskId: `${projOrgSlug(secrets)}:r:${documentId}`,\n documentId: documentId,\n locales: res.data.map((locale: Record<string, any>) => {\n const reviewedStrings = Number(locale['attributes']['reviewed_strings'])\n const totalStrings = Number(locale['attributes']['total_strings'])\n\n return {\n localeId: locale['relationships']['language']['data']['id'].split(':')[1],\n progress:\n Number.isFinite(reviewedStrings) && Number.isFinite(totalStrings) && totalStrings > 0\n ? Math.floor((100 * reviewedStrings) / totalStrings)\n : 0,\n }\n }),\n }))\n\n const locales = await getLocales(secrets)\n const localeIds = locales.map((l: Record<string, any>) => l['localeId'])\n const validLocales = task.locales.filter((locale: Record<string, any>) =>\n localeIds.find((id: string) => id === locale['localeId']),\n )\n task.locales = validLocales\n\n return task\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {getTranslationTask} from './getTranslationTask'\nimport {baseTransifexUrl, projOrgSlug, getHeaders} from './helpers'\n\nconst createResource = async (\n doc: Record<string, any>,\n documentId: string,\n secrets: Secrets | null,\n) => {\n const resourceCreateBody = {\n data: {\n attributes: {\n accept_translations: true,\n name: doc['name'],\n slug: documentId,\n },\n relationships: {\n i18n_format: {\n data: {\n id: 'HTML_FRAGMENT',\n type: 'i18n_formats',\n },\n },\n project: {\n data: {\n id: projOrgSlug(secrets),\n type: 'projects',\n },\n },\n },\n type: 'resources',\n },\n }\n\n const response = await fetch(`${baseTransifexUrl}/resources`, {\n headers: getHeaders(secrets),\n method: 'POST',\n body: JSON.stringify(resourceCreateBody),\n })\n\n if (!response.ok) {\n throw Error(`Failed to create Transifex resource. Status: ${response.status}`)\n }\n\n const res = await response.json()\n const resourceId = res?.data?.id\n\n if (!resourceId) {\n throw Error('Failed to create Transifex resource. Missing resource id in response.')\n }\n\n return resourceId\n}\n\nexport const createTask: Adapter['createTask'] = async (\n documentId: string,\n document: Record<string, any>,\n _localeIds: string[],\n secrets: Secrets | null,\n) => {\n if (!documentId || !secrets) {\n throw Error('Missing documentId or Transifex secrets.')\n }\n\n const resourceResponse = await fetch(\n `${baseTransifexUrl}/resources/${projOrgSlug(secrets)}:r:${documentId}`,\n {headers: getHeaders(secrets)},\n )\n let resourceId: string | null = null\n\n if (resourceResponse.status === 404) {\n resourceId = null\n } else if (!resourceResponse.ok) {\n throw Error(`Failed to retrieve Transifex resource. Status: ${resourceResponse.status}`)\n } else {\n const resource = await resourceResponse.json()\n resourceId = resource.data ? resource.data.id : null\n }\n\n if (!resourceId) {\n resourceId = await createResource(document, documentId, secrets)\n }\n\n const resourceUploadUrl = `${baseTransifexUrl}/resource_strings_async_uploads`\n const resourceUploadBody = {\n data: {\n attributes: {\n content: document['content'],\n content_encoding: 'text',\n },\n relationships: {\n resource: {\n data: {\n id: resourceId,\n type: 'resources',\n },\n },\n },\n type: 'resource_strings_async_uploads',\n },\n }\n\n const uploadResponse = await fetch(resourceUploadUrl, {\n method: 'POST',\n body: JSON.stringify(resourceUploadBody),\n headers: getHeaders(secrets),\n })\n\n if (!uploadResponse.ok) {\n throw Error(`Failed to upload resource strings to Transifex. Status: ${uploadResponse.status}`)\n }\n\n return getTranslationTask(documentId, secrets)\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {baseTransifexUrl, getHeaders} from './helpers'\n\nconst pollForFileDownloadLocation = async (\n resourceDownloadUrl: string,\n translationDownloadId: string,\n headers: Record<string, any>,\n retryCount = 0,\n maxRetries = 20,\n): Promise<string> => {\n const response = await fetch(`${resourceDownloadUrl}/${translationDownloadId}`, {\n headers: headers,\n })\n\n if (retryCount >= maxRetries) {\n throw Error(\n `Failed to retrieve download location for translation download ID ${translationDownloadId} after ${maxRetries} retries.`,\n )\n }\n\n if (response.status === 500) {\n //eslint-disable-next-line no-console -- this is for developer feedback/debugging\n console.info(\n `Transifex plugin message: Received 500 for translation download ID ${translationDownloadId}. Trying to reconnect...`,\n )\n await new Promise((resolve) => setTimeout(resolve, 3000))\n return pollForFileDownloadLocation(\n resourceDownloadUrl,\n translationDownloadId,\n headers,\n retryCount + 1,\n maxRetries,\n )\n } else if (response.redirected) {\n //eslint-disable-next-line no-console -- this is for developer feedback/debugging\n console.info(\n `Transifex plugin message: Received redirect for translation download ID ${translationDownloadId}. Following redirect now for file download.`,\n )\n return response.url\n } else if (response.status === 200) {\n //eslint-disable-next-line no-console -- this is for developer feedback/debugging\n console.info(\n `Transifex plugin message: Requested download location for translation download ID ${translationDownloadId}. Location is still pending, trying again.`,\n )\n await new Promise((resolve) => setTimeout(resolve, 3000))\n return pollForFileDownloadLocation(\n resourceDownloadUrl,\n translationDownloadId,\n headers,\n retryCount + 1,\n maxRetries,\n )\n } else if (response.status === 401 || response.status === 403) {\n throw Error(\n `Failed to retrieve download location for translation download ID ${translationDownloadId}. Status: ${response.status}`,\n )\n }\n console.error(\n `Transifex plugin message: Requested download location for translation download ID ${translationDownloadId} but received error code ${response.status}. Waiting and trying again.`,\n )\n await new Promise((resolve) => setTimeout(resolve, 3000))\n return pollForFileDownloadLocation(\n resourceDownloadUrl,\n translationDownloadId,\n headers,\n retryCount + 1,\n maxRetries,\n )\n}\n\nconst handleFileDownload = (url: string) => {\n return fetch(url).then((res) => res.text())\n}\n\nexport const getTranslation: Adapter['getTranslation'] = async (\n taskId: string,\n localeId: string,\n secrets: Secrets | null,\n) => {\n if (!secrets) {\n throw Error('Missing Transifex secrets.')\n }\n\n const resourceDownloadBody = {\n data: {\n attributes: {\n content_encoding: 'text',\n },\n relationships: {\n language: {\n data: {\n id: `l:${localeId}`,\n type: 'languages',\n },\n },\n resource: {\n data: {\n id: taskId,\n type: 'resources',\n },\n },\n },\n type: 'resource_translations_async_downloads',\n },\n }\n\n const resourceDownloadUrl = `${baseTransifexUrl}/resource_translations_async_downloads`\n const downloadResponse = await fetch(resourceDownloadUrl, {\n headers: getHeaders(secrets),\n method: 'POST',\n body: JSON.stringify(resourceDownloadBody),\n })\n\n if (!downloadResponse.ok) {\n throw Error(\n `Failed to create translation download request in Transifex. Status: ${downloadResponse.status}`,\n )\n }\n\n const download = await downloadResponse.json()\n const translationDownloadId = download?.data?.id\n\n if (!translationDownloadId) {\n throw Error('Failed to create translation download request in Transifex. Missing download id.')\n }\n\n const headers = getHeaders(secrets)\n const location = await pollForFileDownloadLocation(\n resourceDownloadUrl,\n translationDownloadId,\n headers,\n )\n return handleFileDownload(location)\n}\n","import type {Adapter} from 'sanity-translations-tab'\n\nimport {createTask} from './createTask'\nimport {getLocales} from './getLocales'\nimport {getTranslation} from './getTranslation'\nimport {getTranslationTask} from './getTranslationTask'\n\nexport const TransifexAdapter: Adapter = {\n getLocales,\n getTranslationTask,\n createTask,\n getTranslation,\n}\n","import {\n baseDocumentLevelConfig,\n legacyDocumentLevelConfig as baseLegacyDocumentLevelConfig,\n baseFieldLevelConfig,\n baseI18nArrayConfig,\n} from 'sanity-translations-tab'\nimport type {Adapter, TranslationFunctionContext} from 'sanity-translations-tab'\n\nimport {TransifexAdapter} from './transifexAdapter'\n\nexport {\n findLatestDraft,\n BaseDocumentDeserializer,\n BaseDocumentSerializer,\n BaseDocumentMerger,\n defaultStopTypes,\n customSerializers,\n legacyDocumentLevelPatch,\n documentLevelPatch,\n fieldLevelPatch,\n i18nArrayPatch,\n TranslationsTab,\n} from 'sanity-translations-tab'\n\ninterface ConfigOptions {\n adapter: Adapter\n secretsNamespace: string | null\n exportForTranslation: (\n id: string,\n context: TranslationFunctionContext,\n ) => Promise<Record<string, any>>\n importTranslation: (\n id: string,\n localeId: string,\n doc: string,\n context: TranslationFunctionContext,\n ) => Promise<void>\n}\nconst defaultDocumentLevelConfig: ConfigOptions = {\n ...baseDocumentLevelConfig,\n adapter: TransifexAdapter,\n secretsNamespace: 'transifex',\n}\n\nconst legacyDocumentLevelConfig: ConfigOptions = {\n ...baseLegacyDocumentLevelConfig,\n adapter: TransifexAdapter,\n secretsNamespace: 'transifex',\n}\n\nconst defaultFieldLevelConfig: ConfigOptions = {\n ...baseFieldLevelConfig,\n adapter: TransifexAdapter,\n secretsNamespace: 'transifex',\n}\n\n//for documents using sanity-plugin-internationalized-array fields\nconst defaultI18nArrayConfig: ConfigOptions = {\n ...baseI18nArrayConfig,\n adapter: TransifexAdapter,\n secretsNamespace: 'transifex',\n}\n\nexport {\n TransifexAdapter,\n defaultDocumentLevelConfig,\n defaultFieldLevelConfig,\n defaultI18nArrayConfig,\n legacyDocumentLevelConfig,\n}\n"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"index.js","names":["baseLegacyDocumentLevelConfig","\"Authorization\"","\"attributes\"","\"name\"","\"code\"","\"reviewed_strings\"","\"total_strings\"","\"relationships\"","\"language\"","\"data\"","\"id\"","\"localeId\"","\"content\""],"sources":["../src/transifexAdapter/helpers.ts","../src/transifexAdapter/getLocales.ts","../src/transifexAdapter/getTranslationTask.ts","../src/transifexAdapter/createTask.ts","../src/transifexAdapter/getTranslation.ts","../src/transifexAdapter/index.ts","../src/index.ts"],"sourcesContent":["import type {Secrets} from 'sanity-translations-tab'\n\nexport const baseTransifexUrl = 'https://rest.api.transifex.com'\n\nexport const getHeaders = (secrets: Secrets | null): Record<string, string> => ({\n 'Authorization': `Bearer ${secrets?.token}`,\n 'Content-Type': 'application/vnd.api+json',\n})\n\nexport const projOrgSlug = (secrets: Secrets | null): string =>\n `o:${secrets?.organization}:p:${secrets?.project}`\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {baseTransifexUrl, projOrgSlug, getHeaders} from './helpers'\n\nexport const getLocales: Adapter['getLocales'] = async (secrets: Secrets | null) => {\n let locales = []\n if (secrets) {\n const response = await fetch(`${baseTransifexUrl}/projects/${projOrgSlug(secrets)}/languages`, {\n headers: getHeaders(secrets),\n })\n\n if (!response.ok) {\n throw Error(`Failed to retrieve locales from Transifex. Status: ${response.status}`)\n }\n\n locales = await response.json().then((res) =>\n res.data.map((lang: Record<string, any>) => ({\n enabled: true,\n description: lang['attributes']['name'],\n localeId: lang['attributes']['code'],\n })),\n )\n }\n return locales\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {getLocales} from './getLocales'\nimport {baseTransifexUrl, projOrgSlug, getHeaders} from './helpers'\n\nexport const getTranslationTask: Adapter['getTranslationTask'] = async (\n documentId: string,\n secrets: Secrets | null,\n) => {\n if (!documentId || !secrets) {\n return {\n taskId: documentId,\n documentId: documentId,\n locales: [],\n }\n }\n const projectFilter = `filter[project]=${projOrgSlug(secrets)}`\n const resourceFilter = `filter[resource]=${projOrgSlug(secrets)}:r:${documentId}`\n const task = await fetch(\n `${baseTransifexUrl}/resource_language_stats?${projectFilter}&${resourceFilter}`,\n {headers: getHeaders(secrets)},\n )\n .then((res) => {\n if (res.ok) {\n return res.json()\n }\n //normal -- just means that this task doesn't exist yet.\n else if (res.status === 404) {\n return {data: []}\n }\n throw Error(`Failed to retrieve tasks from Transifex. Status: ${res.status}`)\n })\n .then((res) => ({\n taskId: `${projOrgSlug(secrets)}:r:${documentId}`,\n documentId: documentId,\n locales: res.data.map((locale: Record<string, any>) => {\n const reviewedStrings = Number(locale['attributes']['reviewed_strings'])\n const totalStrings = Number(locale['attributes']['total_strings'])\n\n return {\n localeId: locale['relationships']['language']['data']['id'].split(':')[1],\n progress:\n Number.isFinite(reviewedStrings) && Number.isFinite(totalStrings) && totalStrings > 0\n ? Math.floor((100 * reviewedStrings) / totalStrings)\n : 0,\n }\n }),\n }))\n\n const locales = await getLocales(secrets)\n const localeIds = locales.map((l: Record<string, any>) => l['localeId'])\n const validLocales = task.locales.filter((locale: Record<string, any>) =>\n localeIds.find((id: string) => id === locale['localeId']),\n )\n task.locales = validLocales\n\n return task\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {getTranslationTask} from './getTranslationTask'\nimport {baseTransifexUrl, projOrgSlug, getHeaders} from './helpers'\n\nconst createResource = async (\n doc: Record<string, any>,\n documentId: string,\n secrets: Secrets | null,\n) => {\n const resourceCreateBody = {\n data: {\n attributes: {\n accept_translations: true,\n name: doc['name'],\n slug: documentId,\n },\n relationships: {\n i18n_format: {\n data: {\n id: 'HTML_FRAGMENT',\n type: 'i18n_formats',\n },\n },\n project: {\n data: {\n id: projOrgSlug(secrets),\n type: 'projects',\n },\n },\n },\n type: 'resources',\n },\n }\n\n const response = await fetch(`${baseTransifexUrl}/resources`, {\n headers: getHeaders(secrets),\n method: 'POST',\n body: JSON.stringify(resourceCreateBody),\n })\n\n if (!response.ok) {\n throw Error(`Failed to create Transifex resource. Status: ${response.status}`)\n }\n\n const res = await response.json()\n const resourceId = res?.data?.id\n\n if (!resourceId) {\n throw Error('Failed to create Transifex resource. Missing resource id in response.')\n }\n\n return resourceId\n}\n\nexport const createTask: Adapter['createTask'] = async (\n documentId: string,\n document: Record<string, any>,\n _localeIds: string[],\n secrets: Secrets | null,\n) => {\n if (!documentId || !secrets) {\n throw Error('Missing documentId or Transifex secrets.')\n }\n\n const resourceResponse = await fetch(\n `${baseTransifexUrl}/resources/${projOrgSlug(secrets)}:r:${documentId}`,\n {headers: getHeaders(secrets)},\n )\n let resourceId: string | null = null\n\n if (resourceResponse.status === 404) {\n resourceId = null\n } else if (!resourceResponse.ok) {\n throw Error(`Failed to retrieve Transifex resource. Status: ${resourceResponse.status}`)\n } else {\n const resource = await resourceResponse.json()\n resourceId = resource.data ? resource.data.id : null\n }\n\n if (!resourceId) {\n resourceId = await createResource(document, documentId, secrets)\n }\n\n const resourceUploadUrl = `${baseTransifexUrl}/resource_strings_async_uploads`\n const resourceUploadBody = {\n data: {\n attributes: {\n content: document['content'],\n content_encoding: 'text',\n },\n relationships: {\n resource: {\n data: {\n id: resourceId,\n type: 'resources',\n },\n },\n },\n type: 'resource_strings_async_uploads',\n },\n }\n\n const uploadResponse = await fetch(resourceUploadUrl, {\n method: 'POST',\n body: JSON.stringify(resourceUploadBody),\n headers: getHeaders(secrets),\n })\n\n if (!uploadResponse.ok) {\n throw Error(`Failed to upload resource strings to Transifex. Status: ${uploadResponse.status}`)\n }\n\n return getTranslationTask(documentId, secrets)\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {baseTransifexUrl, getHeaders} from './helpers'\n\nconst pollForFileDownloadLocation = async (\n resourceDownloadUrl: string,\n translationDownloadId: string,\n headers: Record<string, any>,\n retryCount = 0,\n maxRetries = 20,\n): Promise<string> => {\n const response = await fetch(`${resourceDownloadUrl}/${translationDownloadId}`, {\n headers: headers,\n })\n\n if (retryCount >= maxRetries) {\n throw Error(\n `Failed to retrieve download location for translation download ID ${translationDownloadId} after ${maxRetries} retries.`,\n )\n }\n\n if (response.status === 500) {\n //eslint-disable-next-line no-console -- this is for developer feedback/debugging\n console.info(\n `Transifex plugin message: Received 500 for translation download ID ${translationDownloadId}. Trying to reconnect...`,\n )\n await new Promise((resolve) => setTimeout(resolve, 3000))\n return pollForFileDownloadLocation(\n resourceDownloadUrl,\n translationDownloadId,\n headers,\n retryCount + 1,\n maxRetries,\n )\n } else if (response.redirected) {\n //eslint-disable-next-line no-console -- this is for developer feedback/debugging\n console.info(\n `Transifex plugin message: Received redirect for translation download ID ${translationDownloadId}. Following redirect now for file download.`,\n )\n return response.url\n } else if (response.status === 200) {\n //eslint-disable-next-line no-console -- this is for developer feedback/debugging\n console.info(\n `Transifex plugin message: Requested download location for translation download ID ${translationDownloadId}. Location is still pending, trying again.`,\n )\n await new Promise((resolve) => setTimeout(resolve, 3000))\n return pollForFileDownloadLocation(\n resourceDownloadUrl,\n translationDownloadId,\n headers,\n retryCount + 1,\n maxRetries,\n )\n } else if (response.status === 401 || response.status === 403) {\n throw Error(\n `Failed to retrieve download location for translation download ID ${translationDownloadId}. Status: ${response.status}`,\n )\n }\n console.error(\n `Transifex plugin message: Requested download location for translation download ID ${translationDownloadId} but received error code ${response.status}. Waiting and trying again.`,\n )\n await new Promise((resolve) => setTimeout(resolve, 3000))\n return pollForFileDownloadLocation(\n resourceDownloadUrl,\n translationDownloadId,\n headers,\n retryCount + 1,\n maxRetries,\n )\n}\n\nconst handleFileDownload = (url: string) => {\n return fetch(url).then((res) => res.text())\n}\n\nexport const getTranslation: Adapter['getTranslation'] = async (\n taskId: string,\n localeId: string,\n secrets: Secrets | null,\n) => {\n if (!secrets) {\n throw Error('Missing Transifex secrets.')\n }\n\n const resourceDownloadBody = {\n data: {\n attributes: {\n content_encoding: 'text',\n },\n relationships: {\n language: {\n data: {\n id: `l:${localeId}`,\n type: 'languages',\n },\n },\n resource: {\n data: {\n id: taskId,\n type: 'resources',\n },\n },\n },\n type: 'resource_translations_async_downloads',\n },\n }\n\n const resourceDownloadUrl = `${baseTransifexUrl}/resource_translations_async_downloads`\n const downloadResponse = await fetch(resourceDownloadUrl, {\n headers: getHeaders(secrets),\n method: 'POST',\n body: JSON.stringify(resourceDownloadBody),\n })\n\n if (!downloadResponse.ok) {\n throw Error(\n `Failed to create translation download request in Transifex. Status: ${downloadResponse.status}`,\n )\n }\n\n const download = await downloadResponse.json()\n const translationDownloadId = download?.data?.id\n\n if (!translationDownloadId) {\n throw Error('Failed to create translation download request in Transifex. Missing download id.')\n }\n\n const headers = getHeaders(secrets)\n const location = await pollForFileDownloadLocation(\n resourceDownloadUrl,\n translationDownloadId,\n headers,\n )\n return handleFileDownload(location)\n}\n","import type {Adapter} from 'sanity-translations-tab'\n\nimport {createTask} from './createTask'\nimport {getLocales} from './getLocales'\nimport {getTranslation} from './getTranslation'\nimport {getTranslationTask} from './getTranslationTask'\n\nexport const TransifexAdapter: Adapter = {\n getLocales,\n getTranslationTask,\n createTask,\n getTranslation,\n}\n","import {\n baseDocumentLevelConfig,\n legacyDocumentLevelConfig as baseLegacyDocumentLevelConfig,\n baseFieldLevelConfig,\n baseI18nArrayConfig,\n} from 'sanity-translations-tab'\nimport type {Adapter, TranslationFunctionContext} from 'sanity-translations-tab'\n\nimport {TransifexAdapter} from './transifexAdapter'\n\nexport {\n findLatestDraft,\n BaseDocumentDeserializer,\n BaseDocumentSerializer,\n BaseDocumentMerger,\n defaultStopTypes,\n customSerializers,\n legacyDocumentLevelPatch,\n documentLevelPatch,\n fieldLevelPatch,\n i18nArrayPatch,\n TranslationsTab,\n} from 'sanity-translations-tab'\n\ninterface ConfigOptions {\n adapter: Adapter\n secretsNamespace: string | null\n exportForTranslation: (\n id: string,\n context: TranslationFunctionContext,\n ) => Promise<Record<string, any>>\n importTranslation: (\n id: string,\n localeId: string,\n doc: string,\n context: TranslationFunctionContext,\n ) => Promise<void>\n}\nconst defaultDocumentLevelConfig: ConfigOptions = {\n ...baseDocumentLevelConfig,\n adapter: TransifexAdapter,\n secretsNamespace: 'transifex',\n}\n\nconst legacyDocumentLevelConfig: ConfigOptions = {\n ...baseLegacyDocumentLevelConfig,\n adapter: TransifexAdapter,\n secretsNamespace: 'transifex',\n}\n\nconst defaultFieldLevelConfig: ConfigOptions = {\n ...baseFieldLevelConfig,\n adapter: TransifexAdapter,\n secretsNamespace: 'transifex',\n}\n\n//for documents using sanity-plugin-internationalized-array fields\nconst defaultI18nArrayConfig: ConfigOptions = {\n ...baseI18nArrayConfig,\n adapter: TransifexAdapter,\n secretsNamespace: 'transifex',\n}\n\nexport {\n TransifexAdapter,\n defaultDocumentLevelConfig,\n defaultFieldLevelConfig,\n defaultI18nArrayConfig,\n legacyDocumentLevelConfig,\n}\n"],"mappings":"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"}
\ No newline at end of file