sanity-plugin-studio-smartling 2.0.6 → 3.0.0-beta
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/LICENSE +21 -0
- package/README.md +204 -74
- package/dist/index.d.ts +53 -11
- package/dist/index.esm.js +227 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +286 -7
- package/dist/index.js.map +1 -0
- package/package.json +76 -47
- package/sanity.json +8 -0
- package/src/adapter/createTask.ts +60 -59
- package/src/adapter/getLocales.ts +16 -9
- package/src/adapter/getTranslation.ts +20 -12
- package/src/adapter/getTranslationTask.ts +28 -19
- package/src/adapter/helpers.ts +30 -16
- package/src/adapter/index.ts +5 -5
- package/src/index.ts +9 -3
- package/src/types.d.ts +0 -0
- package/v2-incompatible.js +11 -0
- package/dist/adapter/createTask.d.ts +0 -12
- package/dist/adapter/getLocales.d.ts +0 -2
- package/dist/adapter/getTranslation.d.ts +0 -2
- package/dist/adapter/getTranslationTask.d.ts +0 -12
- package/dist/adapter/helpers.d.ts +0 -7
- package/dist/adapter/index.d.ts +0 -2
- package/dist/sanity-plugin-studio-smartling.cjs.development.js +0 -1316
- package/dist/sanity-plugin-studio-smartling.cjs.development.js.map +0 -1
- package/dist/sanity-plugin-studio-smartling.cjs.production.min.js +0 -2
- package/dist/sanity-plugin-studio-smartling.cjs.production.min.js.map +0 -1
- package/dist/sanity-plugin-studio-smartling.esm.js +0 -1259
- package/dist/sanity-plugin-studio-smartling.esm.js.map +0 -1
- package/src/3rdparty-typings/sanity-parts.d.ts +0 -1
package/package.json
CHANGED
|
@@ -1,59 +1,88 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"name": "sanity-plugin-studio-smartling",
|
|
3
|
+
"version": "3.0.0-beta",
|
|
4
|
+
"description": "!smartling gif",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"sanity",
|
|
7
|
+
"sanity-plugin"
|
|
8
|
+
],
|
|
9
|
+
"homepage": "https://github.com/sanity-io/sanity-plugin-studio-smartling#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/sanity-io/sanity-plugin-studio-smartling/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git@github.com:sanity-io/sanity-plugin-studio-smartling.git"
|
|
16
|
+
},
|
|
3
17
|
"license": "MIT",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
18
|
+
"author": "Sanity.io",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"source": "./src/index.ts",
|
|
23
|
+
"require": "./dist/index.js",
|
|
24
|
+
"import": "./dist/index.esm.js",
|
|
25
|
+
"default": "./dist/index.esm.js"
|
|
26
|
+
},
|
|
27
|
+
"./package.json": "./package.json"
|
|
28
|
+
},
|
|
29
|
+
"main": "./dist/index.js",
|
|
30
|
+
"module": "./dist/index.esm.js",
|
|
31
|
+
"source": "./src/index.ts",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
6
33
|
"files": [
|
|
7
34
|
"dist",
|
|
8
|
-
"
|
|
35
|
+
"sanity.json",
|
|
36
|
+
"src",
|
|
37
|
+
"v2-incompatible.js"
|
|
9
38
|
],
|
|
10
|
-
"engines": {
|
|
11
|
-
"node": ">=10"
|
|
12
|
-
},
|
|
13
39
|
"scripts": {
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
40
|
+
"build": "run-s clean && plugin-kit verify-package --silent && pkg-utils build --strict && pkg-utils --strict",
|
|
41
|
+
"lint": "eslint . --fix",
|
|
42
|
+
"clean": "rimraf dist",
|
|
43
|
+
"format": "prettier --write --cache --ignore-unknown .",
|
|
44
|
+
"link-watch": "plugin-kit link-watch",
|
|
45
|
+
"prepublishOnly": "run-s build",
|
|
46
|
+
"watch": "pkg-utils watch --strict",
|
|
47
|
+
"prepare": "husky install"
|
|
21
48
|
},
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
"prettier": {
|
|
28
|
-
"printWidth": 80,
|
|
29
|
-
"semi": false,
|
|
30
|
-
"singleQuote": true,
|
|
31
|
-
"trailingComma": "es5"
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@sanity/incompatible-plugin": "^1.0.4",
|
|
51
|
+
"sanity-translations-tab": "^3.0.1"
|
|
32
52
|
},
|
|
33
|
-
"name": "sanity-plugin-studio-smartling",
|
|
34
|
-
"author": "Sanity.io",
|
|
35
|
-
"module": "dist/sanity-plugin-studio-smartling.esm.js",
|
|
36
|
-
"homepage": "https://github.com/sanity-io/sanity-plugin-studio-smartling#readme",
|
|
37
|
-
"size-limit": [
|
|
38
|
-
{
|
|
39
|
-
"path": "dist/sanity-plugin-studio-smartling.cjs.production.min.js",
|
|
40
|
-
"limit": "10 KB"
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
"path": "dist/sanity-plugin-studio-smartling.esm.js",
|
|
44
|
-
"limit": "10 KB"
|
|
45
|
-
}
|
|
46
|
-
],
|
|
47
53
|
"devDependencies": {
|
|
48
|
-
"@
|
|
49
|
-
"@
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"typescript": "^
|
|
54
|
+
"@commitlint/cli": "^17.4.4",
|
|
55
|
+
"@commitlint/config-conventional": "^17.4.4",
|
|
56
|
+
"@sanity/pkg-utils": "^2.2.5",
|
|
57
|
+
"@sanity/plugin-kit": "^3.1.7",
|
|
58
|
+
"@sanity/semantic-release-preset": "^4.0.0",
|
|
59
|
+
"@types/react": "^18.0.28",
|
|
60
|
+
"@typescript-eslint/eslint-plugin": "^5.53.0",
|
|
61
|
+
"@typescript-eslint/parser": "^5.53.0",
|
|
62
|
+
"eslint": "^8.34.0",
|
|
63
|
+
"eslint-config-prettier": "^8.6.0",
|
|
64
|
+
"eslint-config-sanity": "^6.0.0",
|
|
65
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
66
|
+
"eslint-plugin-react": "^7.32.2",
|
|
67
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
68
|
+
"husky": "^8.0.3",
|
|
69
|
+
"lint-staged": "^13.1.2",
|
|
70
|
+
"npm-run-all": "^4.1.5",
|
|
71
|
+
"prettier": "^2.8.4",
|
|
72
|
+
"prettier-plugin-packagejson": "^2.4.3",
|
|
73
|
+
"react": "^18.2.0",
|
|
74
|
+
"react-dom": "^18.2.0",
|
|
75
|
+
"react-is": "^18.2.0",
|
|
76
|
+
"rimraf": "^4.1.2",
|
|
77
|
+
"sanity": "^3.0.0",
|
|
78
|
+
"styled-components": "^5.3.6",
|
|
79
|
+
"typescript": "^4.9.5"
|
|
55
80
|
},
|
|
56
|
-
"
|
|
57
|
-
"
|
|
81
|
+
"peerDependencies": {
|
|
82
|
+
"react": "^18",
|
|
83
|
+
"sanity": "^3"
|
|
84
|
+
},
|
|
85
|
+
"engines": {
|
|
86
|
+
"node": ">=14"
|
|
58
87
|
}
|
|
59
88
|
}
|
package/sanity.json
ADDED
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
findExistingJob,
|
|
6
|
-
} from './helpers'
|
|
7
|
-
import { Secrets } from 'sanity-translations-tab'
|
|
8
|
-
import { getTranslationTask } from './getTranslationTask'
|
|
1
|
+
import {authenticate, getHeaders, findExistingJob} from './helpers'
|
|
2
|
+
import {Adapter, Secrets} from 'sanity-translations-tab'
|
|
3
|
+
import {getTranslationTask} from './getTranslationTask'
|
|
4
|
+
import {Buffer} from 'buffer'
|
|
9
5
|
|
|
10
|
-
const createJob =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
const createJob = (jobName: string, secrets: Secrets, localeIds: string[], accessToken: string) => {
|
|
7
|
+
const {project, proxy} = secrets
|
|
8
|
+
if (!project || !proxy) {
|
|
9
|
+
throw new Error(
|
|
10
|
+
'The Smartling adapter requires a Smartling project identifier and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.'
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const url = `https://api.smartling.com/jobs-api/v3/projects/${project}/jobs`
|
|
15
|
+
return fetch(proxy, {
|
|
18
16
|
method: 'POST',
|
|
19
17
|
headers: {
|
|
20
18
|
...getHeaders(url, accessToken),
|
|
@@ -25,8 +23,8 @@ const createJob = async (
|
|
|
25
23
|
targetLocaleIds: localeIds,
|
|
26
24
|
}),
|
|
27
25
|
})
|
|
28
|
-
.then(res => res.json())
|
|
29
|
-
.then(res => res.response.data.translationJobUid)
|
|
26
|
+
.then((res) => res.json())
|
|
27
|
+
.then((res) => res.response.data.translationJobUid)
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
/* we're using batches here because it eliminates some
|
|
@@ -34,20 +32,28 @@ const createJob = async (
|
|
|
34
32
|
* and is able to be used for new bulk
|
|
35
33
|
* job functionality.
|
|
36
34
|
*/
|
|
37
|
-
|
|
35
|
+
|
|
36
|
+
const createJobBatch = (
|
|
38
37
|
jobId: string,
|
|
39
|
-
|
|
38
|
+
secrets: Secrets,
|
|
40
39
|
documentName: string,
|
|
41
40
|
accessToken: string,
|
|
42
41
|
localeIds: string[],
|
|
43
42
|
workflowUid?: string
|
|
43
|
+
//eslint-disable-next-line max-params
|
|
44
44
|
) => {
|
|
45
|
-
const
|
|
45
|
+
const {project, proxy} = secrets
|
|
46
|
+
if (!project || !proxy) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
'The Smartling adapter requires a Smartling project identifier and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.'
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
const url = `https://api.smartling.com/job-batches-api/v2/projects/${project}/batches`
|
|
46
52
|
const reqBody: {
|
|
47
53
|
authorize: boolean
|
|
48
54
|
translationJobUid: string
|
|
49
55
|
fileUris: string[]
|
|
50
|
-
localeWorkflows?: {
|
|
56
|
+
localeWorkflows?: {targetLocaleId: string; workflowUid: string}[]
|
|
51
57
|
} = {
|
|
52
58
|
authorize: true,
|
|
53
59
|
translationJobUid: jobId,
|
|
@@ -55,13 +61,13 @@ const createJobBatch = async (
|
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
if (workflowUid) {
|
|
58
|
-
reqBody.localeWorkflows = localeIds.map(l => ({
|
|
64
|
+
reqBody.localeWorkflows = localeIds.map((l) => ({
|
|
59
65
|
targetLocaleId: l,
|
|
60
66
|
workflowUid,
|
|
61
67
|
}))
|
|
62
68
|
}
|
|
63
69
|
|
|
64
|
-
return fetch(
|
|
70
|
+
return fetch(proxy, {
|
|
65
71
|
method: 'POST',
|
|
66
72
|
headers: {
|
|
67
73
|
...getHeaders(url, accessToken),
|
|
@@ -69,75 +75,70 @@ const createJobBatch = async (
|
|
|
69
75
|
},
|
|
70
76
|
body: JSON.stringify(reqBody),
|
|
71
77
|
})
|
|
72
|
-
.then(res => res.json())
|
|
73
|
-
.then(res => res.response.data.batchUid)
|
|
78
|
+
.then((res) => res.json())
|
|
79
|
+
.then((res) => res.response.data.batchUid)
|
|
74
80
|
}
|
|
75
81
|
|
|
76
|
-
const uploadFileToBatch =
|
|
82
|
+
const uploadFileToBatch = (
|
|
77
83
|
batchUid: string,
|
|
78
84
|
document: Record<string, any>,
|
|
79
|
-
|
|
85
|
+
secrets: Secrets,
|
|
80
86
|
localeIds: string[],
|
|
81
87
|
accessToken: string
|
|
82
88
|
) => {
|
|
83
|
-
const
|
|
89
|
+
const {project, proxy} = secrets
|
|
90
|
+
if (!project || !proxy) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
'The Smartling adapter requires a Smartling project identifier and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.'
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
const url = `https://api.smartling.com/job-batches-api/v2/projects/${project}/batches/${batchUid}/file`
|
|
84
96
|
const formData = new FormData()
|
|
85
97
|
formData.append('fileUri', document.name)
|
|
86
98
|
formData.append('fileType', 'html')
|
|
87
99
|
const htmlBuffer = Buffer.from(document.content, 'utf-8')
|
|
88
100
|
formData.append('file', new Blob([htmlBuffer]), `${document.name}.html`)
|
|
89
|
-
localeIds.forEach(localeId =>
|
|
90
|
-
formData.append('localeIdsToAuthorize[]', localeId)
|
|
91
|
-
)
|
|
101
|
+
localeIds.forEach((localeId) => formData.append('localeIdsToAuthorize[]', localeId))
|
|
92
102
|
|
|
93
|
-
return fetch(
|
|
103
|
+
return fetch(proxy, {
|
|
94
104
|
method: 'POST',
|
|
95
105
|
headers: getHeaders(url, accessToken),
|
|
96
106
|
body: formData,
|
|
97
|
-
}).then(res => res.json())
|
|
107
|
+
}).then((res) => res.json())
|
|
98
108
|
}
|
|
99
109
|
|
|
100
|
-
|
|
110
|
+
//@ts-ignore until return TranslationTask type is added to sanity-translations-tab
|
|
111
|
+
export const createTask: Adapter['createTask'] = async (
|
|
101
112
|
documentId: string,
|
|
102
113
|
document: Record<string, any>,
|
|
103
114
|
localeIds: string[],
|
|
104
|
-
secrets: Secrets,
|
|
115
|
+
secrets: Secrets | null,
|
|
105
116
|
workflowUid?: string
|
|
106
117
|
) => {
|
|
107
|
-
|
|
118
|
+
if (!secrets?.project || !secrets?.secret || !secrets?.proxy) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
'The Smartling adapter requires a project ID, a secret key, and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.'
|
|
121
|
+
)
|
|
122
|
+
}
|
|
108
123
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
secrets.project,
|
|
113
|
-
accessToken
|
|
114
|
-
)
|
|
124
|
+
const accessToken = await authenticate(secrets)
|
|
125
|
+
|
|
126
|
+
let taskId = await findExistingJob(document.name, secrets, accessToken)
|
|
115
127
|
if (!taskId) {
|
|
116
|
-
taskId = await createJob(
|
|
117
|
-
document.name,
|
|
118
|
-
secrets.project,
|
|
119
|
-
localeIds,
|
|
120
|
-
accessToken
|
|
121
|
-
)
|
|
128
|
+
taskId = await createJob(document.name, secrets, localeIds, accessToken)
|
|
122
129
|
}
|
|
123
130
|
|
|
124
|
-
//TODO: log errors here if needed
|
|
125
131
|
const batchUid = await createJobBatch(
|
|
126
132
|
taskId,
|
|
127
|
-
secrets
|
|
133
|
+
secrets,
|
|
128
134
|
document.name,
|
|
129
135
|
accessToken,
|
|
130
136
|
localeIds,
|
|
131
137
|
workflowUid
|
|
132
138
|
)
|
|
133
|
-
const uploadFileRes = await uploadFileToBatch(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
secrets.project,
|
|
137
|
-
localeIds,
|
|
138
|
-
accessToken
|
|
139
|
-
)
|
|
140
|
-
console.log('upload status', uploadFileRes)
|
|
139
|
+
const uploadFileRes = await uploadFileToBatch(batchUid, document, secrets, localeIds, accessToken)
|
|
140
|
+
//eslint-disable-next-line no-console -- for developer debugging
|
|
141
|
+
console.info('Upload status from Smartling: ', uploadFileRes)
|
|
141
142
|
|
|
142
143
|
return getTranslationTask(documentId, secrets)
|
|
143
144
|
}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {authenticate, getHeaders} from './helpers'
|
|
2
|
+
import {Secrets} from 'sanity-translations-tab'
|
|
3
|
+
import {Adapter} from 'sanity-translations-tab'
|
|
3
4
|
|
|
4
|
-
export const getLocales = async (secrets: Secrets) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
export const getLocales: Adapter['getLocales'] = async (secrets: Secrets | null) => {
|
|
6
|
+
if (!secrets?.project || !secrets?.secret || !secrets?.proxy) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
'The Smartling adapter requires a project ID, a secret key, and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.'
|
|
9
|
+
)
|
|
10
|
+
}
|
|
11
|
+
const {project, proxy} = secrets
|
|
12
|
+
const url = `https://api.smartling.com/projects-api/v2/projects/${project}`
|
|
13
|
+
const accessToken = await authenticate(secrets)
|
|
14
|
+
return fetch(proxy, {
|
|
15
|
+
method: 'GET',
|
|
9
16
|
headers: getHeaders(url, accessToken),
|
|
10
17
|
})
|
|
11
|
-
.then(res => res.json())
|
|
12
|
-
.then(res => res.response.data.targetLocales)
|
|
18
|
+
.then((res) => res.json())
|
|
19
|
+
.then((res) => res.response.data.targetLocales)
|
|
13
20
|
}
|
|
@@ -1,27 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Secrets
|
|
1
|
+
import {authenticate, getHeaders} from './helpers'
|
|
2
|
+
import {Adapter, Secrets} from 'sanity-translations-tab'
|
|
3
3
|
|
|
4
|
-
export const getTranslation = async (
|
|
4
|
+
export const getTranslation: Adapter['getTranslation'] = async (
|
|
5
5
|
taskId: string,
|
|
6
6
|
localeId: string,
|
|
7
|
-
secrets: Secrets
|
|
7
|
+
secrets: Secrets | null
|
|
8
8
|
) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
if (!secrets?.project || !secrets?.secret || !secrets?.proxy) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
'The Smartling adapter requires a project ID, a secret key, and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.'
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const {project, proxy} = secrets
|
|
16
|
+
|
|
17
|
+
const url = `https://api.smartling.com/files-api/v2/projects/${project}/locales/${localeId}/file?fileUri=${taskId}&retrievalType=pending`
|
|
18
|
+
const accessToken = await authenticate(secrets)
|
|
19
|
+
const translatedHTML = await fetch(proxy, {
|
|
20
|
+
method: 'GET',
|
|
13
21
|
headers: getHeaders(url, accessToken),
|
|
14
22
|
})
|
|
15
|
-
.then(res => res.json())
|
|
16
|
-
.then(res => {
|
|
23
|
+
.then((res) => res.json())
|
|
24
|
+
.then((res) => {
|
|
17
25
|
if (res.body) {
|
|
18
26
|
return res.body
|
|
19
27
|
} else if (res.response.errors) {
|
|
20
28
|
const errMsg =
|
|
21
|
-
res.response.errors[0]?.message ||
|
|
22
|
-
'Error retrieving translation from Smartling'
|
|
29
|
+
res.response.errors[0]?.message || 'Error retrieving translation from Smartling'
|
|
23
30
|
throw new Error(errMsg)
|
|
24
31
|
}
|
|
32
|
+
return ''
|
|
25
33
|
})
|
|
26
34
|
|
|
27
35
|
return translatedHTML
|
|
@@ -1,17 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
authenticate,
|
|
4
|
-
getHeaders,
|
|
5
|
-
findExistingJob,
|
|
6
|
-
} from './helpers'
|
|
7
|
-
import { Secrets } from 'sanity-translations-tab'
|
|
1
|
+
import {authenticate, getHeaders, findExistingJob} from './helpers'
|
|
2
|
+
import {Adapter, Secrets} from 'sanity-translations-tab'
|
|
8
3
|
|
|
9
|
-
|
|
4
|
+
interface SmartlingProgressItem {
|
|
5
|
+
targetLocaleId: string
|
|
6
|
+
progress: {
|
|
7
|
+
percentComplete: number
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const getTranslationTask: Adapter['getTranslationTask'] = async (
|
|
10
12
|
documentId: string,
|
|
11
|
-
secrets: Secrets
|
|
13
|
+
secrets: Secrets | null
|
|
12
14
|
) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
if (!secrets?.project || !secrets?.secret || !secrets?.proxy) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
'The Smartling adapter requires a project ID, a secret key, and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.'
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const {project, proxy} = secrets
|
|
22
|
+
|
|
23
|
+
const accessToken = await authenticate(secrets)
|
|
24
|
+
const taskId = await findExistingJob(documentId, secrets, accessToken)
|
|
15
25
|
if (!taskId) {
|
|
16
26
|
return {
|
|
17
27
|
documentId,
|
|
@@ -20,18 +30,17 @@ export const getTranslationTask = async (
|
|
|
20
30
|
}
|
|
21
31
|
}
|
|
22
32
|
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
method: 'POST',
|
|
33
|
+
const progressUrl = `https://api.smartling.com/jobs-api/v3/projects/${project}/jobs/${taskId}/progress`
|
|
34
|
+
const smartlingTask = await fetch(proxy, {
|
|
35
|
+
method: 'GET',
|
|
27
36
|
headers: getHeaders(progressUrl, accessToken),
|
|
28
37
|
})
|
|
29
|
-
.then(res => res.json())
|
|
30
|
-
.then(res => res.response.data)
|
|
38
|
+
.then((res) => res.json())
|
|
39
|
+
.then((res) => res.response.data)
|
|
31
40
|
|
|
32
41
|
let locales = []
|
|
33
42
|
if (smartlingTask && smartlingTask.contentProgressReport) {
|
|
34
|
-
locales = smartlingTask.contentProgressReport.map(item => ({
|
|
43
|
+
locales = smartlingTask.contentProgressReport.map((item: SmartlingProgressItem) => ({
|
|
35
44
|
localeId: item.targetLocaleId,
|
|
36
45
|
progress: item.progress ? item.progress.percentComplete : 0,
|
|
37
46
|
}))
|
|
@@ -42,6 +51,6 @@ export const getTranslationTask = async (
|
|
|
42
51
|
locales,
|
|
43
52
|
//since our download is tied to document id for smartling, keep track of it as a task
|
|
44
53
|
taskId: documentId,
|
|
45
|
-
linkToVendorTask: `https://dashboard.smartling.com/app/projects/${
|
|
54
|
+
linkToVendorTask: `https://dashboard.smartling.com/app/projects/${project}/account-jobs/${project}:${taskId}`,
|
|
46
55
|
}
|
|
47
56
|
}
|
package/src/adapter/helpers.ts
CHANGED
|
@@ -1,49 +1,63 @@
|
|
|
1
|
-
|
|
1
|
+
import {Secrets} from 'sanity-translations-tab'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
interface Headers {
|
|
4
|
+
[key: string]: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const authenticate = (secrets: Secrets): Promise<string> => {
|
|
4
8
|
const url = 'https://api.smartling.com/auth-api/v2/authenticate'
|
|
5
9
|
const headers = {
|
|
6
10
|
'content-type': 'application/json',
|
|
7
11
|
'X-URL': url,
|
|
8
12
|
}
|
|
9
|
-
|
|
13
|
+
const {secret, proxy} = secrets
|
|
14
|
+
if (!secret || !proxy) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
'The Smartling adapter requires a secret key and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.'
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
return fetch(proxy, {
|
|
10
20
|
headers,
|
|
11
21
|
method: 'POST',
|
|
12
22
|
body: JSON.stringify(secret),
|
|
13
23
|
})
|
|
14
|
-
.then(res => res.json())
|
|
15
|
-
.then(res => res.response.data.accessToken)
|
|
24
|
+
.then((res) => res.json())
|
|
25
|
+
.then((res) => res.response.data.accessToken)
|
|
16
26
|
}
|
|
17
27
|
|
|
18
|
-
export const getHeaders = (url: string, accessToken: string) => ({
|
|
28
|
+
export const getHeaders = (url: string, accessToken: string): Headers => ({
|
|
19
29
|
Authorization: `Bearer ${accessToken}`,
|
|
20
30
|
'X-URL': url,
|
|
21
31
|
})
|
|
22
32
|
|
|
23
|
-
export const findExistingJob =
|
|
33
|
+
export const findExistingJob = (
|
|
24
34
|
documentId: string,
|
|
25
|
-
|
|
35
|
+
secrets: Secrets,
|
|
26
36
|
accessToken: string
|
|
27
37
|
): Promise<string> => {
|
|
28
|
-
const
|
|
29
|
-
|
|
38
|
+
const {project, proxy} = secrets
|
|
39
|
+
if (!project || !proxy) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
'The Smartling adapter requires a Smartling project identifier and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.'
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
const url = `https://api.smartling.com/jobs-api/v3/projects/${project}/jobs?jobName=${documentId}`
|
|
45
|
+
return fetch(proxy, {
|
|
30
46
|
method: 'POST',
|
|
31
47
|
headers: getHeaders(url, accessToken),
|
|
32
48
|
})
|
|
33
|
-
.then(res => res.json())
|
|
34
|
-
.then(res => {
|
|
49
|
+
.then((res) => res.json())
|
|
50
|
+
.then((res) => {
|
|
35
51
|
if (res.response.data.items.length) {
|
|
36
52
|
//smartling will fuzzy match job names. We need to be precise.
|
|
37
53
|
const correctJob = res.response.data.items.find(
|
|
38
|
-
item => item.jobName && item.jobName === documentId
|
|
54
|
+
(item: {jobName: string}) => item.jobName && item.jobName === documentId
|
|
39
55
|
)
|
|
40
56
|
if (correctJob) {
|
|
41
57
|
return correctJob.translationJobUid
|
|
42
|
-
} else {
|
|
43
|
-
return ''
|
|
44
58
|
}
|
|
45
|
-
} else {
|
|
46
59
|
return ''
|
|
47
60
|
}
|
|
61
|
+
return ''
|
|
48
62
|
})
|
|
49
63
|
}
|
package/src/adapter/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import {Adapter} from 'sanity-translations-tab'
|
|
2
|
+
import {getLocales} from './getLocales'
|
|
3
|
+
import {getTranslationTask} from './getTranslationTask'
|
|
4
|
+
import {createTask} from './createTask'
|
|
5
|
+
import {getTranslation} from './getTranslation'
|
|
6
6
|
|
|
7
7
|
export const SmartlingAdapter: Adapter = {
|
|
8
8
|
getLocales,
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {SerializedDocument} from 'sanity-naive-html-serializer'
|
|
1
2
|
import {
|
|
2
3
|
TranslationsTab,
|
|
3
4
|
baseDocumentLevelConfig,
|
|
@@ -11,17 +12,22 @@ import {
|
|
|
11
12
|
Adapter,
|
|
12
13
|
documentLevelPatch,
|
|
13
14
|
fieldLevelPatch,
|
|
15
|
+
TranslationFunctionContext,
|
|
14
16
|
} from 'sanity-translations-tab'
|
|
15
|
-
import {
|
|
17
|
+
import {SmartlingAdapter} from './adapter'
|
|
16
18
|
|
|
17
19
|
interface ConfigOptions {
|
|
18
20
|
adapter: Adapter
|
|
19
21
|
secretsNamespace: string | null
|
|
20
|
-
exportForTranslation: (
|
|
22
|
+
exportForTranslation: (
|
|
23
|
+
id: string,
|
|
24
|
+
context: TranslationFunctionContext
|
|
25
|
+
) => Promise<SerializedDocument>
|
|
21
26
|
importTranslation: (
|
|
22
27
|
id: string,
|
|
23
28
|
localeId: string,
|
|
24
|
-
doc: string
|
|
29
|
+
doc: string,
|
|
30
|
+
context: TranslationFunctionContext
|
|
25
31
|
) => Promise<void>
|
|
26
32
|
}
|
|
27
33
|
const defaultDocumentLevelConfig: ConfigOptions = {
|
package/src/types.d.ts
ADDED
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const {showIncompatiblePluginDialog} = require('@sanity/incompatible-plugin')
|
|
2
|
+
const {name, version, sanityExchangeUrl} = require('./package.json')
|
|
3
|
+
|
|
4
|
+
export default showIncompatiblePluginDialog({
|
|
5
|
+
name: name,
|
|
6
|
+
versions: {
|
|
7
|
+
v3: version,
|
|
8
|
+
v2: undefined,
|
|
9
|
+
},
|
|
10
|
+
sanityExchangeUrl,
|
|
11
|
+
})
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { Secrets } from 'sanity-translations-tab';
|
|
2
|
-
export declare const createTask: (documentId: string, document: Record<string, any>, localeIds: string[], secrets: Secrets, workflowUid?: string) => Promise<{
|
|
3
|
-
documentId: string;
|
|
4
|
-
taskId: string;
|
|
5
|
-
locales: any[];
|
|
6
|
-
linkToVendorTask?: undefined;
|
|
7
|
-
} | {
|
|
8
|
-
documentId: string;
|
|
9
|
-
locales: any[];
|
|
10
|
-
taskId: string;
|
|
11
|
-
linkToVendorTask: string;
|
|
12
|
-
}>;
|