sanity-plugin-transifex
5.1.115.1.12
~
Modified (4 files)
Index: package/dist/index.js
===================================================================
--- package/dist/index.js
+++ package/dist/index.js
@@ -123,9 +123,10 @@
});
if (!downloadResponse.ok) throw Error(`Failed to create translation download request in Transifex. Status: ${downloadResponse.status}`);
let translationDownloadId = (await downloadResponse.json())?.data?.id;
if (!translationDownloadId) throw Error("Failed to create translation download request in Transifex. Missing download id.");
- return handleFileDownload(await pollForFileDownloadLocation(resourceDownloadUrl, translationDownloadId, getHeaders(secrets)));
+ let headers = getHeaders(secrets), location = await pollForFileDownloadLocation(resourceDownloadUrl, translationDownloadId, headers);
+ return handleFileDownload(location);
}
}, defaultDocumentLevelConfig = {
...baseDocumentLevelConfig,
adapter: TransifexAdapter, Index: package/package.json
===================================================================
--- package/package.json
+++ package/package.json
@@ -1,7 +1,7 @@
{
"name": "sanity-plugin-transifex",
- "version": "5.1.11",
+ "version": "5.1.12",
"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,21 +26,21 @@
".": "./dist/index.js",
"./package.json": "./package.json"
},
"dependencies": {
- "sanity-translations-tab": "^6.1.11"
+ "sanity-translations-tab": "^6.1.12"
},
"devDependencies": {
"@sanity/tsconfig": "^2.2.0",
- "@sanity/tsdown-config": "^0.11.0",
+ "@sanity/tsdown-config": "^0.13.1",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"babel-plugin-react-compiler": "^1.0.0",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"sanity": "^6.3.0",
"styled-components": "^6.4.3",
- "tsdown": "^0.22.3"
+ "tsdown": "^0.22.5"
},
"peerDependencies": {
"react": "^19.2",
"react-dom": "^19.2", Index: package/dist/index.d.ts.map
===================================================================
--- package/dist/index.d.ts.map
+++ package/dist/index.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"index.d.ts","names":[],"sources":["../src/transifexAdapter/index.ts","../src/index.ts"],"mappings":";cAOa,gBAAA,EAAkB,OAK9B;AAAA,UCYS,aAAA;EACR,OAAA,EAAS,OAAA;EACT,gBAAA;EACA,oBAAA,GACE,EAAA,UACA,OAAA,EAAS,0BAAA,KACN,OAAA,CAAQ,MAAA;EACb,iBAAA,GACE,EAAA,UACA,QAAA,UACA,GAAA,UACA,OAAA,EAAS,0BAAA,KACN,OAAA;AAAA;AAAA,cAED,0BAAA,EAA4B,aAIjC;AAAA,cAEK,yBAAA,EAA2B,aAIhC;AAAA,cAEK,uBAAA,EAAyB,aAI9B;AAAA,cAGK,sBAAA,EAAwB,aAI7B"}
\ No newline at end of file
+{"version":3,"file":"index.d.ts","names":[],"sources":["../src/transifexAdapter/index.ts","../src/index.ts"],"mappings":";cAOa,kBAAkB;UCiBrB;EACR,SAAS;EACT;EACA,uBACE,YACA,SAAS,+BACN,QAAQ;EACb,oBACE,YACA,kBACA,aACA,SAAS,+BACN;;cAED,4BAA4B;cAM5B,2BAA2B;cAM3B,yBAAyB;cAOzB,wBAAwB"}
\ No newline at end of file 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":["Secrets","baseTransifexUrl","getHeaders","secrets","Record","token","projOrgSlug","organization","project","Adapter","Secrets","baseTransifexUrl","projOrgSlug","getHeaders","getLocales","secrets","locales","response","fetch","headers","ok","Error","status","json","then","res","data","map","lang","Record","enabled","description","localeId","Adapter","Secrets","getLocales","baseTransifexUrl","projOrgSlug","getHeaders","getTranslationTask","documentId","secrets","taskId","locales","projectFilter","resourceFilter","task","fetch","headers","then","res","ok","json","status","data","Error","map","locale","Record","reviewedStrings","Number","totalStrings","localeId","split","progress","isFinite","Math","floor","localeIds","l","validLocales","filter","find","id","Adapter","Secrets","getTranslationTask","baseTransifexUrl","projOrgSlug","getHeaders","createResource","doc","Record","documentId","secrets","resourceCreateBody","data","attributes","accept_translations","name","slug","relationships","i18n_format","id","type","project","response","fetch","headers","method","body","JSON","stringify","ok","Error","status","res","json","resourceId","createTask","document","_localeIds","resourceResponse","resource","resourceUploadUrl","resourceUploadBody","content","content_encoding","uploadResponse","Adapter","Secrets","baseTransifexUrl","getHeaders","pollForFileDownloadLocation","resourceDownloadUrl","translationDownloadId","headers","Record","retryCount","maxRetries","Promise","response","fetch","Error","status","console","info","resolve","setTimeout","redirected","url","error","handleFileDownload","then","res","text","getTranslation","taskId","localeId","secrets","resourceDownloadBody","data","attributes","content_encoding","relationships","language","id","type","resource","downloadResponse","method","body","JSON","stringify","ok","download","json","location","Adapter","createTask","getLocales","getTranslation","getTranslationTask","TransifexAdapter","baseDocumentLevelConfig","legacyDocumentLevelConfig","baseLegacyDocumentLevelConfig","baseFieldLevelConfig","baseI18nArrayConfig","Adapter","TranslationFunctionContext","TransifexAdapter","findLatestDraft","BaseDocumentDeserializer","BaseDocumentSerializer","BaseDocumentMerger","defaultStopTypes","customSerializers","legacyDocumentLevelPatch","documentLevelPatch","fieldLevelPatch","i18nArrayPatch","TranslationsTab","ConfigOptions","adapter","secretsNamespace","exportForTranslation","id","context","Promise","Record","importTranslation","localeId","doc","defaultDocumentLevelConfig","defaultFieldLevelConfig","defaultI18nArrayConfig"],"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":["Secrets","baseTransifexUrl","getHeaders","secrets","Record","token","projOrgSlug","organization","project","Adapter","Secrets","baseTransifexUrl","projOrgSlug","getHeaders","getLocales","secrets","locales","response","fetch","headers","ok","Error","status","json","then","res","data","map","lang","Record","enabled","description","localeId","Adapter","Secrets","getLocales","baseTransifexUrl","projOrgSlug","getHeaders","getTranslationTask","documentId","secrets","taskId","locales","projectFilter","resourceFilter","task","fetch","headers","then","res","ok","json","status","data","Error","map","locale","Record","reviewedStrings","Number","totalStrings","localeId","split","progress","isFinite","Math","floor","localeIds","l","validLocales","filter","find","id","Adapter","Secrets","getTranslationTask","baseTransifexUrl","projOrgSlug","getHeaders","createResource","doc","Record","documentId","secrets","resourceCreateBody","data","attributes","accept_translations","name","slug","relationships","i18n_format","id","type","project","response","fetch","headers","method","body","JSON","stringify","ok","Error","status","res","json","resourceId","createTask","document","_localeIds","resourceResponse","resource","resourceUploadUrl","resourceUploadBody","content","content_encoding","uploadResponse","Adapter","Secrets","baseTransifexUrl","getHeaders","pollForFileDownloadLocation","resourceDownloadUrl","translationDownloadId","headers","Record","retryCount","maxRetries","Promise","response","fetch","Error","status","console","info","resolve","setTimeout","redirected","url","error","handleFileDownload","then","res","text","getTranslation","taskId","localeId","secrets","resourceDownloadBody","data","attributes","content_encoding","relationships","language","id","type","resource","downloadResponse","method","body","JSON","stringify","ok","download","json","location","Adapter","createTask","getLocales","getTranslation","getTranslationTask","TransifexAdapter","baseDocumentLevelConfig","legacyDocumentLevelConfig","baseLegacyDocumentLevelConfig","baseFieldLevelConfig","baseI18nArrayConfig","Adapter","TranslationFunctionContext","TransifexAdapter","findLatestDraft","BaseDocumentDeserializer","BaseDocumentSerializer","BaseDocumentMerger","defaultStopTypes","customSerializers","legacyDocumentLevelPatch","documentLevelPatch","fieldLevelPatch","i18nArrayPatch","TranslationsTab","ConfigOptions","adapter","secretsNamespace","exportForTranslation","id","context","Promise","Record","importTranslation","localeId","doc","defaultDocumentLevelConfig","defaultFieldLevelConfig","defaultI18nArrayConfig"],"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