sanity-plugin-transifex 1.1.2 → 2.0.2

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/helpers.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import { SanityDocument } from '@sanity/types';
2
- export declare const findLatestDraft: (documentId: string) => any;
3
- export declare const findDocumentAtRevision: (documentId: string, rev: string) => Promise<any>;
4
- export declare const documentLevelPatch: (documentId: string, translatedFields: SanityDocument, localeId: string) => Promise<void>;
5
- export declare const fieldLevelPatch: (documentId: string, translatedFields: SanityDocument, localeId: string) => Promise<void>;
package/src/helpers.ts DELETED
@@ -1,114 +0,0 @@
1
- import { SanityDocument } from '@sanity/types'
2
- import sanityClient from 'part:@sanity/base/client'
3
- import { BaseDocumentMerger } from 'sanity-naive-html-serializer'
4
-
5
- const client = sanityClient.withConfig({ apiVersion: '2021-03-25' })
6
-
7
- //document fetch
8
- export const findLatestDraft = (documentId: string) => {
9
- //eliminates i18n versions
10
- const query = `*[_id == $id || _id == $draftId]`
11
- const params = { id: `${documentId}`, draftId: `drafts.${documentId}` }
12
- return client
13
- .fetch(query, params)
14
- .then(
15
- (docs: SanityDocument[]) =>
16
- docs.find(doc => doc._id.includes('draft')) ?? docs[0]
17
- )
18
- }
19
-
20
- //revision fetch
21
- export const findDocumentAtRevision = async (
22
- documentId: string,
23
- rev: string
24
- ) => {
25
- const dataset = client.config().dataset
26
- let baseUrl = `/data/history/${dataset}/documents/${documentId}?revision=${rev}`
27
- let url = client.getUrl(baseUrl)
28
- let revisionDoc = await fetch(url, { credentials: 'include' })
29
- .then(req => req.json())
30
- .then(req => req.documents[0])
31
- /* endpoint will silently give you incorrect doc
32
- * if you don't request draft and the rev belongs to a draft, so check
33
- */
34
- if (!revisionDoc || revisionDoc._rev !== rev) {
35
- baseUrl = `/data/history/${dataset}/documents/drafts.${documentId}?revision=${rev}`
36
- url = client.getUrl(baseUrl)
37
- revisionDoc = await fetch(url, { credentials: 'include' })
38
- .then(req => req.json())
39
- .then(req => req.documents[0])
40
- }
41
- return revisionDoc
42
- }
43
-
44
- //document-level patch
45
- export const documentLevelPatch = async (
46
- documentId: string,
47
- translatedFields: SanityDocument,
48
- localeId: string
49
- ) => {
50
- let baseDoc: SanityDocument
51
- if (translatedFields._rev) {
52
- baseDoc = await findDocumentAtRevision(documentId, translatedFields._rev)
53
- } else {
54
- baseDoc = await findLatestDraft(documentId)
55
- }
56
-
57
- const merged = BaseDocumentMerger.documentLevelMerge(
58
- translatedFields,
59
- baseDoc
60
- )
61
- const targetId = `i18n.${documentId}.${localeId}`
62
- const i18nDoc = await findLatestDraft(targetId)
63
-
64
- if (i18nDoc) {
65
- const cleanedMerge: Record<string, any> = {}
66
- //don't overwrite any existing values on the i18n doc
67
- Object.entries(merged).forEach(([key, value]) => {
68
- if (
69
- Object.keys(translatedFields).includes(key) &&
70
- !['_id', '_rev', '_updatedAt'].includes(key)
71
- ) {
72
- cleanedMerge[key] = value
73
- }
74
- })
75
- client
76
- .transaction()
77
- //@ts-ignore
78
- .patch(i18nDoc._id, p => p.set(cleanedMerge))
79
- .commit()
80
- } else {
81
- merged._id = `drafts.${targetId}`
82
- //account for legacy implementations of i18n plugin lang
83
- if (baseDoc._lang) {
84
- merged._lang = localeId
85
- } else if (baseDoc.__i18n_lang) {
86
- merged.__i18n_lang = localeId
87
- }
88
- client.create(merged)
89
- }
90
- }
91
-
92
- //field level patch
93
- export const fieldLevelPatch = async (
94
- documentId: string,
95
- translatedFields: SanityDocument,
96
- localeId: string
97
- ) => {
98
- let baseDoc: SanityDocument
99
- if (translatedFields._rev) {
100
- baseDoc = await findDocumentAtRevision(documentId, translatedFields._rev)
101
- } else {
102
- baseDoc = await findLatestDraft(documentId)
103
- }
104
- const merged = BaseDocumentMerger.fieldLevelMerge(
105
- translatedFields,
106
- baseDoc,
107
- localeId,
108
- 'en'
109
- )
110
- client
111
- .patch(baseDoc._id)
112
- .set(merged)
113
- .commit()
114
- }
@@ -1,230 +0,0 @@
1
- import { Adapter, Secrets } from 'sanity-translations-tab'
2
-
3
- const baseTransifexUrl = 'https://rest.api.transifex.com'
4
- const getHeaders = (secrets: Secrets | null) => ({
5
- Authorization: `Bearer ${secrets?.token}`,
6
- 'Content-Type': 'application/vnd.api+json',
7
- })
8
- const projOrgSlug = (secrets: Secrets | null) =>
9
- `o:${secrets?.organization}:p:${secrets?.project}`
10
-
11
- const getLocales = async (secrets: Secrets | null) => {
12
- if (secrets) {
13
- return fetch(
14
- `${baseTransifexUrl}/projects/${projOrgSlug(secrets)}/languages`,
15
- { headers: getHeaders(secrets) }
16
- )
17
- .then(res => res.json())
18
- .then(res =>
19
- res.data.map((lang: Record<string, any>) => ({
20
- enabled: true,
21
- description: lang.attributes.name,
22
- localeId: lang.attributes.code,
23
- }))
24
- )
25
- } else {
26
- return []
27
- }
28
- }
29
-
30
- const getTranslationTask = async (
31
- documentId: string,
32
- secrets: Secrets | null
33
- ) => {
34
- if (!documentId || !secrets) {
35
- return {
36
- taskId: documentId,
37
- documentId: documentId,
38
- locales: [],
39
- }
40
- }
41
- const projectFilter = `filter[project]=${projOrgSlug(secrets)}`
42
- const resourceFilter = `filter[resource]=${projOrgSlug(
43
- secrets
44
- )}:r:${documentId}`
45
- const task = await fetch(
46
- `${baseTransifexUrl}/resource_language_stats?${projectFilter}&${resourceFilter}`,
47
- { headers: getHeaders(secrets) }
48
- )
49
- .then(res => {
50
- if (res.ok) {
51
- return res.json()
52
- }
53
- //normal -- just means that this task doesn't exist yet.
54
- else if (res.status === 404) {
55
- return { data: [] }
56
- } else {
57
- throw Error(
58
- `Failed to retrieve tasks from Transifex. Status: ${res.status}`
59
- )
60
- }
61
- })
62
- .then(res => ({
63
- taskId: `${projOrgSlug(secrets)}:r:${documentId}`,
64
- documentId: documentId,
65
- locales: res.data.map((locale: Record<string, any>) => ({
66
- localeId: locale.relationships.language.data.id.split(':')[1],
67
- progress: Math.floor(
68
- 100 *
69
- (locale.attributes.reviewed_strings /
70
- parseFloat(locale.attributes.total_strings))
71
- ),
72
- })),
73
- }))
74
-
75
- const locales = await getLocales(secrets)
76
- const localeIds = locales.map((l: Record<string, any>) => l.localeId)
77
- const validLocales = task.locales.filter((locale: Record<string, any>) =>
78
- localeIds.find((id: string) => id === locale.localeId)
79
- )
80
- task.locales = validLocales
81
-
82
- return task
83
- }
84
-
85
- const createResource = async (
86
- doc: Record<string, any>,
87
- documentId: string,
88
- secrets: Secrets | null
89
- ) => {
90
- const resourceCreateBody = {
91
- data: {
92
- attributes: {
93
- accept_translations: true,
94
- name: doc.name,
95
- slug: documentId,
96
- },
97
- relationships: {
98
- i18n_format: {
99
- data: {
100
- id: 'HTML_FRAGMENT',
101
- type: 'i18n_formats',
102
- },
103
- },
104
- project: {
105
- data: {
106
- id: projOrgSlug(secrets),
107
- type: 'projects',
108
- },
109
- },
110
- },
111
- type: 'resources',
112
- },
113
- }
114
-
115
- return fetch(`${baseTransifexUrl}/resources`, {
116
- headers: getHeaders(secrets),
117
- method: 'POST',
118
- body: JSON.stringify(resourceCreateBody),
119
- })
120
- .then(res => res.json())
121
- .then(res => res.data.id)
122
- }
123
-
124
- const createTask = async (
125
- documentId: string,
126
- document: Record<string, any>,
127
- //unfortunately Transifex doesn't let you specify locales on creating a task
128
- //@ts-ignore
129
- localeIds: string[],
130
- secrets: Secrets | null
131
- ) => {
132
- let resourceId = await fetch(
133
- `${baseTransifexUrl}/resources/${projOrgSlug(secrets)}:r:${documentId}`,
134
- { headers: getHeaders(secrets) }
135
- )
136
- .then(res => res.json())
137
- .then(res => (res.data ? res.data.id : null))
138
-
139
- if (!resourceId) {
140
- resourceId = await createResource(document, documentId, secrets)
141
- }
142
-
143
- const resourceUploadUrl = `${baseTransifexUrl}/resource_strings_async_uploads`
144
- const resourceUploadBody = {
145
- data: {
146
- attributes: {
147
- content: document.content,
148
- content_encoding: 'text',
149
- },
150
- relationships: {
151
- resource: {
152
- data: {
153
- id: resourceId,
154
- type: 'resources',
155
- },
156
- },
157
- },
158
- type: 'resource_strings_async_uploads',
159
- },
160
- }
161
-
162
- return fetch(resourceUploadUrl, {
163
- method: 'POST',
164
- body: JSON.stringify(resourceUploadBody),
165
- headers: getHeaders(secrets),
166
- }).then(() => getTranslationTask(documentId, secrets))
167
- }
168
-
169
- const getTranslation = async (
170
- taskId: string,
171
- localeId: string,
172
- secrets: Secrets | null
173
- ) => {
174
- const resourceDownloadBody = {
175
- data: {
176
- attributes: {
177
- content_encoding: 'text',
178
- },
179
- relationships: {
180
- language: {
181
- data: {
182
- id: `l:${localeId}`,
183
- type: 'languages',
184
- },
185
- },
186
- resource: {
187
- data: {
188
- id: taskId,
189
- type: 'resources',
190
- },
191
- },
192
- },
193
- type: 'resource_translations_async_downloads',
194
- },
195
- }
196
-
197
- const resourceDownloadUrl = `${baseTransifexUrl}/resource_translations_async_downloads`
198
- const translationDownloadId = await fetch(resourceDownloadUrl, {
199
- headers: getHeaders(secrets),
200
- method: 'POST',
201
- body: JSON.stringify(resourceDownloadBody),
202
- })
203
- .then(res => res.json())
204
- .then(res => res.data.id)
205
-
206
- return new Promise(resolve => {
207
- setTimeout(function() {
208
- fetch(`${resourceDownloadUrl}/${translationDownloadId}`, {
209
- headers: getHeaders(secrets),
210
- }).then(res => {
211
- if (res.redirected) {
212
- return resolve(handleFileDownload(res.url))
213
- } else {
214
- return res.json()
215
- }
216
- })
217
- }, 3000)
218
- })
219
- }
220
-
221
- const handleFileDownload = async (url: string) => {
222
- return fetch(url).then(res => res.text())
223
- }
224
-
225
- export const TransifexAdapter: Adapter = {
226
- getLocales,
227
- getTranslationTask,
228
- createTask,
229
- getTranslation,
230
- }