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/index.d.ts +10 -15
- package/dist/sanity-plugin-transifex.cjs.development.js +492 -1063
- package/dist/sanity-plugin-transifex.cjs.development.js.map +1 -1
- package/dist/sanity-plugin-transifex.cjs.production.min.js +1 -1
- package/dist/sanity-plugin-transifex.cjs.production.min.js.map +1 -1
- package/dist/sanity-plugin-transifex.esm.js +466 -1053
- package/dist/sanity-plugin-transifex.esm.js.map +1 -1
- package/dist/transifexAdapter/createTask.d.ts +6 -0
- package/dist/transifexAdapter/getLocales.d.ts +2 -0
- package/dist/transifexAdapter/getTranslation.d.ts +2 -0
- package/dist/transifexAdapter/getTranslationTask.d.ts +6 -0
- package/dist/transifexAdapter/helpers.d.ts +7 -0
- package/dist/{transifexAdapter.d.ts → transifexAdapter/index.d.ts} +0 -0
- package/package.json +2 -2
- package/src/index.ts +25 -30
- package/src/transifexAdapter/createTask.ts +87 -0
- package/src/transifexAdapter/getLocales.ts +21 -0
- package/src/transifexAdapter/getTranslation.ts +102 -0
- package/src/transifexAdapter/getTranslationTask.ts +58 -0
- package/src/transifexAdapter/helpers.ts +11 -0
- package/src/transifexAdapter/index.ts +13 -0
- package/dist/helpers.d.ts +0 -5
- package/src/helpers.ts +0 -114
- package/src/transifexAdapter.ts +0 -230
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
|
-
}
|
package/src/transifexAdapter.ts
DELETED
|
@@ -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
|
-
}
|