locize-cli 11.0.0 → 12.0.0
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/CHANGELOG.md +12 -0
- package/LICENSE +1 -1
- package/README.md +1 -0
- package/dist/cjs/add.js +90 -0
- package/{bin/locize → dist/cjs/cli.js} +390 -670
- package/dist/cjs/combineSubkeyPreprocessor.js +155 -0
- package/dist/cjs/convertToDesiredFormat.js +205 -0
- package/dist/cjs/convertToFlatFormat.js +231 -0
- package/dist/cjs/copyVersion.js +60 -0
- package/dist/cjs/createBranch.js +59 -0
- package/dist/cjs/deleteBranch.js +89 -0
- package/dist/cjs/deleteNamespace.js +37 -0
- package/dist/cjs/download.js +376 -0
- package/dist/cjs/filterNamespaces.js +13 -0
- package/dist/cjs/format.js +156 -0
- package/dist/cjs/formats.js +33 -0
- package/dist/cjs/get.js +66 -0
- package/dist/cjs/getBranches.js +37 -0
- package/dist/cjs/getJob.js +37 -0
- package/dist/cjs/getProjectStats.js +37 -0
- package/dist/cjs/getRemoteLanguages.js +38 -0
- package/dist/cjs/getRemoteNamespace.js +125 -0
- package/dist/cjs/index.js +37 -0
- package/dist/cjs/isValidUuid.js +6 -0
- package/dist/cjs/lngs.js +215 -0
- package/dist/cjs/mapLimit.js +22 -0
- package/dist/cjs/mergeBranch.js +80 -0
- package/dist/cjs/migrate.js +239 -0
- package/dist/cjs/missing.js +162 -0
- package/dist/cjs/package.json +5 -0
- package/{parseLocalLanguage.js → dist/cjs/parseLocalLanguage.js} +135 -142
- package/dist/cjs/parseLocalLanguages.js +18 -0
- package/dist/cjs/parseLocalReference.js +11 -0
- package/dist/cjs/publishVersion.js +42 -0
- package/dist/cjs/removeUndefinedFromArrays.js +19 -0
- package/dist/cjs/removeVersion.js +42 -0
- package/dist/cjs/request.js +66 -0
- package/dist/cjs/shouldUnflatten.js +21 -0
- package/dist/cjs/sortFlatResources.js +13 -0
- package/dist/cjs/sync.js +772 -0
- package/dist/cjs/unflatten.js +81 -0
- package/dist/esm/add.js +88 -0
- package/dist/esm/cli.js +1020 -0
- package/{combineSubkeyPreprocessor.js → dist/esm/combineSubkeyPreprocessor.js} +70 -73
- package/dist/esm/convertToDesiredFormat.js +203 -0
- package/dist/esm/convertToFlatFormat.js +229 -0
- package/dist/esm/copyVersion.js +58 -0
- package/dist/esm/createBranch.js +57 -0
- package/dist/esm/deleteBranch.js +87 -0
- package/dist/esm/deleteNamespace.js +35 -0
- package/dist/esm/download.js +374 -0
- package/{filterNamespaces.js → dist/esm/filterNamespaces.js} +4 -4
- package/dist/esm/format.js +154 -0
- package/{formats.js → dist/esm/formats.js} +7 -11
- package/dist/esm/get.js +64 -0
- package/dist/esm/getBranches.js +35 -0
- package/dist/esm/getJob.js +35 -0
- package/dist/esm/getProjectStats.js +35 -0
- package/dist/esm/getRemoteLanguages.js +36 -0
- package/dist/esm/getRemoteNamespace.js +123 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/isValidUuid.js +4 -0
- package/dist/esm/lngs.js +213 -0
- package/dist/esm/mapLimit.js +20 -0
- package/dist/esm/mergeBranch.js +78 -0
- package/dist/esm/migrate.js +237 -0
- package/dist/esm/missing.js +160 -0
- package/dist/esm/parseLocalLanguage.js +194 -0
- package/dist/esm/parseLocalLanguages.js +16 -0
- package/dist/esm/parseLocalReference.js +9 -0
- package/dist/esm/publishVersion.js +40 -0
- package/{removeUndefinedFromArrays.js → dist/esm/removeUndefinedFromArrays.js} +5 -5
- package/dist/esm/removeVersion.js +40 -0
- package/dist/esm/request.js +64 -0
- package/{shouldUnflatten.js → dist/esm/shouldUnflatten.js} +7 -7
- package/dist/esm/sortFlatResources.js +11 -0
- package/dist/esm/sync.js +770 -0
- package/{unflatten.js → dist/esm/unflatten.js} +36 -34
- package/package.json +39 -18
- package/rollup.config.js +57 -0
- package/add.js +0 -105
- package/convertToDesiredFormat.js +0 -268
- package/convertToFlatFormat.js +0 -322
- package/copyVersion.js +0 -69
- package/createBranch.js +0 -61
- package/deleteBranch.js +0 -97
- package/deleteNamespace.js +0 -39
- package/download.js +0 -516
- package/format.js +0 -206
- package/get.js +0 -81
- package/getBranches.js +0 -40
- package/getJob.js +0 -40
- package/getProjectStats.js +0 -40
- package/getRemoteLanguages.js +0 -40
- package/getRemoteNamespace.js +0 -122
- package/index.js +0 -9
- package/isValidUuid.js +0 -2
- package/lngs.json +0 -211
- package/mergeBranch.js +0 -102
- package/migrate.js +0 -314
- package/missing.js +0 -169
- package/parseLocalLanguages.js +0 -22
- package/parseLocalReference.js +0 -10
- package/publishVersion.js +0 -64
- package/removeVersion.js +0 -64
- package/request.js +0 -64
- package/sortFlatResources.js +0 -9
- package/sync.js +0 -786
package/sync.js
DELETED
|
@@ -1,786 +0,0 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const { mkdirp } = require('mkdirp')
|
|
4
|
-
const rimraf = require('rimraf')
|
|
5
|
-
const async = require('async')
|
|
6
|
-
const colors = require('colors')
|
|
7
|
-
const request = require('./request')
|
|
8
|
-
const flatten = require('flat')
|
|
9
|
-
const cloneDeep = require('lodash.clonedeep')
|
|
10
|
-
const getRemoteNamespace = require('./getRemoteNamespace')
|
|
11
|
-
const getRemoteLanguages = require('./getRemoteLanguages')
|
|
12
|
-
const convertToDesiredFormat = require('./convertToDesiredFormat')
|
|
13
|
-
const parseLocalLanguages = require('./parseLocalLanguages')
|
|
14
|
-
const parseLocalReference = require('./parseLocalReference')
|
|
15
|
-
const formats = require('./formats')
|
|
16
|
-
const lngCodes = require('./lngs.json')
|
|
17
|
-
const deleteNamespace = require('./deleteNamespace')
|
|
18
|
-
const getProjectStats = require('./getProjectStats')
|
|
19
|
-
const reversedFileExtensionsMap = formats.reversedFileExtensionsMap
|
|
20
|
-
const locize2xcstrings = require('locize-xcstrings/cjs/locize2xcstrings')
|
|
21
|
-
const getBranches = require('./getBranches')
|
|
22
|
-
const isValidUuid = require('./isValidUuid')
|
|
23
|
-
|
|
24
|
-
const getDirectories = (srcpath) => {
|
|
25
|
-
return fs.readdirSync(srcpath).filter((file) => {
|
|
26
|
-
return fs.statSync(path.join(srcpath, file)).isDirectory()
|
|
27
|
-
})
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function getInfosInUrl (download) {
|
|
31
|
-
const splitted = download.key.split('/')
|
|
32
|
-
const version = splitted[download.isPrivate ? 2 : 1]
|
|
33
|
-
const language = splitted[download.isPrivate ? 3 : 2]
|
|
34
|
-
const namespace = splitted[download.isPrivate ? 4 : 3]
|
|
35
|
-
return { version, language, namespace }
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const getDownloads = (opt, cb) => {
|
|
39
|
-
if (!opt.unpublished) {
|
|
40
|
-
request(opt.apiEndpoint + '/download/' + opt.projectId + '/' + opt.version, {
|
|
41
|
-
method: 'get',
|
|
42
|
-
headers: opt.apiKey
|
|
43
|
-
? {
|
|
44
|
-
Authorization: opt.apiKey
|
|
45
|
-
}
|
|
46
|
-
: undefined
|
|
47
|
-
}, (err, res, obj) => {
|
|
48
|
-
if (err) return cb(err)
|
|
49
|
-
if (res.status >= 300) {
|
|
50
|
-
if (obj && (obj.errorMessage || obj.message)) {
|
|
51
|
-
if (res.statusText && res.status) {
|
|
52
|
-
return cb(new Error(res.statusText + ' (' + res.status + ') | ' + (obj.errorMessage || obj.message)))
|
|
53
|
-
}
|
|
54
|
-
return cb(new Error((obj.errorMessage || obj.message)))
|
|
55
|
-
}
|
|
56
|
-
return cb(new Error(res.statusText + ' (' + res.status + ')'))
|
|
57
|
-
}
|
|
58
|
-
if (obj.length > 0) {
|
|
59
|
-
if (opt.skipEmpty) obj = obj.filter((d) => d.size > 2)
|
|
60
|
-
return cb(null, obj)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
getProjectStats(opt, (err, res) => {
|
|
64
|
-
if (err) return handleError(err, cb)
|
|
65
|
-
if (!res) return handleError(new Error('Nothing found!'), cb)
|
|
66
|
-
if (!res[opt.version]) return handleError(new Error(`Version "${opt.version}" not found!`), cb)
|
|
67
|
-
|
|
68
|
-
return cb(null, obj)
|
|
69
|
-
})
|
|
70
|
-
})
|
|
71
|
-
} else {
|
|
72
|
-
getProjectStats(opt, (err, res) => {
|
|
73
|
-
if (err) return handleError(err, cb)
|
|
74
|
-
if (!res) return handleError(new Error('Nothing found!'), cb)
|
|
75
|
-
if (!res[opt.version]) return handleError(new Error(`Version "${opt.version}" not found!`), cb)
|
|
76
|
-
|
|
77
|
-
const toDownload = []
|
|
78
|
-
const lngsToCheck = opt.language ? [opt.language] : (opt.languages && opt.languages.length > 0) ? opt.languages : Object.keys(res[opt.version])
|
|
79
|
-
lngsToCheck.forEach((l) => {
|
|
80
|
-
if (opt.namespaces) {
|
|
81
|
-
opt.namespaces.forEach((n) => {
|
|
82
|
-
if (!res[opt.version][l][n]) return
|
|
83
|
-
if (opt.skipEmpty && res[opt.version][l][n].segmentsTranslated === 0) return
|
|
84
|
-
toDownload.push({
|
|
85
|
-
url: `${opt.apiEndpoint}/${opt.projectId}/${opt.version}/${l}/${n}`,
|
|
86
|
-
key: `${opt.projectId}/${opt.version}/${l}/${n}`,
|
|
87
|
-
lastModified: '1960-01-01T00:00:00.000Z',
|
|
88
|
-
size: 0
|
|
89
|
-
})
|
|
90
|
-
})
|
|
91
|
-
} else if (opt.namespace) {
|
|
92
|
-
if (!res[opt.version][l][opt.namespace]) return
|
|
93
|
-
if (opt.skipEmpty && res[opt.version][l][opt.namespace].segmentsTranslated === 0) return
|
|
94
|
-
toDownload.push({
|
|
95
|
-
url: `${opt.apiEndpoint}/${opt.projectId}/${opt.version}/${l}/${opt.namespace}`,
|
|
96
|
-
key: `${opt.projectId}/${opt.version}/${l}/${opt.namespace}`,
|
|
97
|
-
lastModified: '1960-01-01T00:00:00.000Z',
|
|
98
|
-
size: 0
|
|
99
|
-
})
|
|
100
|
-
} else {
|
|
101
|
-
Object.keys(res[opt.version][l]).forEach((n) => {
|
|
102
|
-
if (opt.skipEmpty && res[opt.version][l][n].segmentsTranslated === 0) return
|
|
103
|
-
toDownload.push({
|
|
104
|
-
url: `${opt.apiEndpoint}/${opt.projectId}/${opt.version}/${l}/${n}`,
|
|
105
|
-
key: `${opt.projectId}/${opt.version}/${l}/${n}`,
|
|
106
|
-
lastModified: '1960-01-01T00:00:00.000Z',
|
|
107
|
-
size: 0
|
|
108
|
-
})
|
|
109
|
-
})
|
|
110
|
-
}
|
|
111
|
-
})
|
|
112
|
-
cb(null, toDownload)
|
|
113
|
-
})
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const compareNamespace = (local, remote, lastModifiedLocal, lastModifiedRemote) => {
|
|
118
|
-
const wasLastChangedRemote = lastModifiedLocal && lastModifiedRemote && lastModifiedLocal.getTime() < lastModifiedRemote.getTime()
|
|
119
|
-
const diff = {
|
|
120
|
-
toAdd: [],
|
|
121
|
-
toAddLocally: [],
|
|
122
|
-
toUpdate: [],
|
|
123
|
-
toUpdateLocally: [],
|
|
124
|
-
toRemove: [],
|
|
125
|
-
toRemoveLocally: []
|
|
126
|
-
}
|
|
127
|
-
local = local || {}
|
|
128
|
-
remote = remote || {}
|
|
129
|
-
Object.keys(local).forEach((k) => {
|
|
130
|
-
if (remote[k] === '' && local[k] === '') return
|
|
131
|
-
if (!remote[k]) {
|
|
132
|
-
if (wasLastChangedRemote) {
|
|
133
|
-
diff.toRemoveLocally.push(k) // will download later
|
|
134
|
-
} else {
|
|
135
|
-
diff.toAdd.push(k)
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (
|
|
139
|
-
remote[k] && (
|
|
140
|
-
(typeof local[k] === 'object' && local[k] && local[k].value && remote[k] !== local[k].value) ||
|
|
141
|
-
(typeof local[k] !== 'object' && remote[k] !== local[k])
|
|
142
|
-
)
|
|
143
|
-
) {
|
|
144
|
-
if (wasLastChangedRemote) {
|
|
145
|
-
diff.toUpdateLocally.push(k) // will download later
|
|
146
|
-
} else {
|
|
147
|
-
diff.toUpdate.push(k)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
})
|
|
151
|
-
Object.keys(remote).forEach((k) => {
|
|
152
|
-
if (local[k] === '' && remote[k] === '') return
|
|
153
|
-
if (!local[k]) {
|
|
154
|
-
if (wasLastChangedRemote) {
|
|
155
|
-
diff.toAddLocally.push(k) // will download later
|
|
156
|
-
} else {
|
|
157
|
-
diff.toRemove.push(k)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
})
|
|
161
|
-
return diff
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const compareNamespaces = (opt, localNamespaces, cb) => {
|
|
165
|
-
async.mapLimit(localNamespaces, 20, (ns, clb) => {
|
|
166
|
-
getRemoteNamespace(opt, ns.language, ns.namespace, (err, remoteNamespace, lastModified) => {
|
|
167
|
-
if (err) return clb(err)
|
|
168
|
-
|
|
169
|
-
const diff = compareNamespace(ns.content, remoteNamespace, opt.compareModificationTime ? ns.mtime : undefined, opt.compareModificationTime ? lastModified : undefined)
|
|
170
|
-
ns.diff = diff
|
|
171
|
-
ns.remoteContent = remoteNamespace
|
|
172
|
-
clb(null, ns)
|
|
173
|
-
})
|
|
174
|
-
}, cb)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const getNamespaceNamesAvailableInReference = (opt, downloads) => {
|
|
178
|
-
const nsNames = []
|
|
179
|
-
downloads.forEach((d) => {
|
|
180
|
-
const splitted = d.key.split('/')
|
|
181
|
-
const lng = splitted[2]
|
|
182
|
-
const ns = splitted[3]
|
|
183
|
-
if (lng === opt.referenceLanguage) {
|
|
184
|
-
nsNames.push(ns)
|
|
185
|
-
}
|
|
186
|
-
})
|
|
187
|
-
return nsNames
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const ensureAllNamespacesInLanguages = (opt, remoteLanguages, downloads) => {
|
|
191
|
-
const namespaces = getNamespaceNamesAvailableInReference(opt, downloads)
|
|
192
|
-
|
|
193
|
-
remoteLanguages.forEach((lng) => {
|
|
194
|
-
namespaces.forEach((n) => {
|
|
195
|
-
const found = downloads.find((d) => d.key === `${opt.projectId}/${opt.version}/${lng}/${n}`)
|
|
196
|
-
if (!found) {
|
|
197
|
-
downloads.push({
|
|
198
|
-
key: `${opt.projectId}/${opt.version}/${lng}/${n}`,
|
|
199
|
-
lastModified: '1960-01-01T00:00:00.000Z',
|
|
200
|
-
size: 0,
|
|
201
|
-
url: `${opt.apiEndpoint}/${opt.projectId}/${opt.version}/${lng}/${n}`
|
|
202
|
-
})
|
|
203
|
-
}
|
|
204
|
-
})
|
|
205
|
-
})
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const downloadAll = (opt, remoteLanguages, omitRef, manipulate, cb) => {
|
|
209
|
-
if (typeof cb !== 'function') {
|
|
210
|
-
if (typeof manipulate === 'function') {
|
|
211
|
-
cb = manipulate
|
|
212
|
-
manipulate = undefined
|
|
213
|
-
}
|
|
214
|
-
if (typeof omitRef === 'function') {
|
|
215
|
-
cb = omitRef
|
|
216
|
-
manipulate = undefined
|
|
217
|
-
omitRef = false
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (!opt.dry && opt.format !== 'xcstrings') cleanupLanguages(opt, remoteLanguages)
|
|
222
|
-
|
|
223
|
-
getDownloads(opt, (err, downloads) => {
|
|
224
|
-
if (err) return cb(err)
|
|
225
|
-
|
|
226
|
-
ensureAllNamespacesInLanguages(opt, remoteLanguages, downloads)
|
|
227
|
-
|
|
228
|
-
if (omitRef) {
|
|
229
|
-
downloads = downloads.filter((d) => {
|
|
230
|
-
const splitted = d.key.split('/')
|
|
231
|
-
const lng = splitted[d.isPrivate ? 3 : 2]
|
|
232
|
-
return lng !== opt.referenceLanguage
|
|
233
|
-
})
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (opt.format === 'xcstrings') { // 1 file per namespace including all languages
|
|
237
|
-
const downloadsByNamespace = {}
|
|
238
|
-
downloads.forEach((download) => {
|
|
239
|
-
const { namespace } = getInfosInUrl(download)
|
|
240
|
-
downloadsByNamespace[namespace] = downloadsByNamespace[namespace] || []
|
|
241
|
-
downloadsByNamespace[namespace].push(download)
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
async.eachLimit(Object.keys(downloadsByNamespace), opt.unpublished ? 5 : 20, (namespace, clb) => {
|
|
245
|
-
const locizeData = {
|
|
246
|
-
sourceLng: opt.referenceLanguage,
|
|
247
|
-
resources: {}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
async.eachLimit(downloadsByNamespace[namespace], opt.unpublished ? 5 : 20, (download, clb) => {
|
|
251
|
-
const { language } = getInfosInUrl(download)
|
|
252
|
-
opt.isPrivate = download.isPrivate
|
|
253
|
-
|
|
254
|
-
if (opt.language && opt.language !== language && language !== opt.referenceLanguage) return clb(null)
|
|
255
|
-
if (opt.languages && opt.languages.length > 0 && opt.languages.indexOf(language) < 0 && language !== opt.referenceLanguage) return clb(null)
|
|
256
|
-
if (opt.namespace && opt.namespace !== namespace) return clb(null)
|
|
257
|
-
if (opt.namespaces && opt.namespaces.length > 0 && opt.namespaces.indexOf(namespace) < 0) return clb(null)
|
|
258
|
-
|
|
259
|
-
if (opt.unpublished) opt.raw = true
|
|
260
|
-
getRemoteNamespace(opt, language, namespace, (err, ns, lastModified) => {
|
|
261
|
-
if (err) return clb(err)
|
|
262
|
-
|
|
263
|
-
if (opt.skipEmpty && Object.keys(flatten(ns)).length === 0) {
|
|
264
|
-
return clb(null)
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
if (manipulate && typeof manipulate === 'function') manipulate(language, namespace, ns)
|
|
268
|
-
|
|
269
|
-
locizeData.resources[language] = ns
|
|
270
|
-
clb()
|
|
271
|
-
})
|
|
272
|
-
}, (err) => {
|
|
273
|
-
if (err) return clb(err)
|
|
274
|
-
|
|
275
|
-
try {
|
|
276
|
-
const converted = locize2xcstrings(locizeData)
|
|
277
|
-
|
|
278
|
-
const filledMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, '').replace(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`, namespace) + reversedFileExtensionsMap[opt.format]
|
|
279
|
-
if (opt.dry) return clb(null)
|
|
280
|
-
if (opt.pathMask.indexOf(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`) > opt.pathMask.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) && filledMask.lastIndexOf(path.sep) > 0) {
|
|
281
|
-
mkdirp.sync(path.join(opt.path, filledMask.substring(0, filledMask.lastIndexOf(path.sep))))
|
|
282
|
-
}
|
|
283
|
-
const parentDir = path.dirname(path.join(opt.path, filledMask))
|
|
284
|
-
mkdirp.sync(parentDir)
|
|
285
|
-
const fileContent = (opt.format !== 'xlsx' && !converted.endsWith('\n')) ? (converted + '\n') : converted
|
|
286
|
-
fs.writeFile(path.join(opt.path, filledMask), fileContent, clb)
|
|
287
|
-
} catch (e) {
|
|
288
|
-
err.message = 'Invalid content for "' + opt.format + '" format!\n' + (err.message || '')
|
|
289
|
-
return clb(err)
|
|
290
|
-
}
|
|
291
|
-
})
|
|
292
|
-
}, cb)
|
|
293
|
-
} else { // 1 file per namespace/lng
|
|
294
|
-
async.eachLimit(downloads, opt.unpublished ? 5 : 20, (download, clb) => {
|
|
295
|
-
const { language, namespace } = getInfosInUrl(download)
|
|
296
|
-
opt.isPrivate = download.isPrivate
|
|
297
|
-
|
|
298
|
-
if (opt.language && opt.language !== language && language !== opt.referenceLanguage) return clb(null)
|
|
299
|
-
if (opt.languages && opt.languages.length > 0 && opt.languages.indexOf(language) < 0 && language !== opt.referenceLanguage) return clb(null)
|
|
300
|
-
if (opt.namespace && opt.namespace !== namespace) return clb(null)
|
|
301
|
-
if (opt.namespaces && opt.namespaces.length > 0 && opt.namespaces.indexOf(namespace) < 0) return clb(null)
|
|
302
|
-
|
|
303
|
-
getRemoteNamespace(opt, language, namespace, (err, ns, lastModified) => {
|
|
304
|
-
if (err) return clb(err)
|
|
305
|
-
|
|
306
|
-
if (opt.skipEmpty && Object.keys(flatten(ns)).length === 0) {
|
|
307
|
-
return clb(null)
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
if (manipulate && typeof manipulate === 'function') manipulate(language, namespace, ns)
|
|
311
|
-
|
|
312
|
-
convertToDesiredFormat(opt, namespace, language, ns, lastModified, (err, converted) => {
|
|
313
|
-
if (err) {
|
|
314
|
-
err.message = 'Invalid content for "' + opt.format + '" format!\n' + (err.message || '')
|
|
315
|
-
return clb(err)
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const filledMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, language).replace(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`, namespace) + reversedFileExtensionsMap[opt.format]
|
|
319
|
-
if (opt.dry) return clb(null)
|
|
320
|
-
if (opt.pathMask.indexOf(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`) > opt.pathMask.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) && filledMask.lastIndexOf(path.sep) > 0) {
|
|
321
|
-
mkdirp.sync(path.join(opt.path, filledMask.substring(0, filledMask.lastIndexOf(path.sep))))
|
|
322
|
-
}
|
|
323
|
-
const parentDir = path.dirname(path.join(opt.path, filledMask))
|
|
324
|
-
mkdirp.sync(parentDir)
|
|
325
|
-
const fileContent = (opt.format !== 'xlsx' && !converted.endsWith('\n')) ? (converted + '\n') : converted
|
|
326
|
-
fs.writeFile(path.join(opt.path, filledMask), fileContent, clb)
|
|
327
|
-
})
|
|
328
|
-
})
|
|
329
|
-
}, cb)
|
|
330
|
-
}
|
|
331
|
-
})
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const update = (opt, lng, ns, shouldOmit, cb) => {
|
|
335
|
-
const data = {}
|
|
336
|
-
if (!opt.skipDelete) {
|
|
337
|
-
ns.diff.toRemove.forEach((k) => { data[k] = null })
|
|
338
|
-
}
|
|
339
|
-
ns.diff.toAdd.forEach((k) => { data[k] = ns.content[k] })
|
|
340
|
-
if (opt.updateValues) {
|
|
341
|
-
ns.diff.toUpdate.forEach((k) => { data[k] = ns.content[k] })
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const keysToSend = Object.keys(data).length
|
|
345
|
-
if (keysToSend === 0) return cb(null)
|
|
346
|
-
|
|
347
|
-
if (opt.dry) return cb(null)
|
|
348
|
-
|
|
349
|
-
const payloadKeysLimit = 1000
|
|
350
|
-
|
|
351
|
-
function send (d, so, clb, isRetrying) {
|
|
352
|
-
const queryParams = new URLSearchParams()
|
|
353
|
-
if (opt.autoTranslate && lng === opt.referenceLanguage) {
|
|
354
|
-
/** @See https://www.locize.com/docs/api#optional-autotranslate */
|
|
355
|
-
queryParams.append('autotranslate', 'true')
|
|
356
|
-
}
|
|
357
|
-
if (so) {
|
|
358
|
-
queryParams.append('omitstatsgeneration', 'true')
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
const queryString = queryParams.size > 0 ? '?' + queryParams.toString() : ''
|
|
362
|
-
|
|
363
|
-
request(opt.apiEndpoint + '/update/' + opt.projectId + '/' + opt.version + '/' + lng + '/' + ns.namespace + queryString, {
|
|
364
|
-
method: 'post',
|
|
365
|
-
body: d,
|
|
366
|
-
headers: {
|
|
367
|
-
Authorization: opt.apiKey
|
|
368
|
-
}
|
|
369
|
-
}, (err, res, obj) => {
|
|
370
|
-
if (err) return clb(err)
|
|
371
|
-
const cliInfo = res.headers.get('x-cli-info')
|
|
372
|
-
if (cliInfo && cliInfo !== opt.lastShownCliInfo) {
|
|
373
|
-
console.log(colors.yellow(cliInfo))
|
|
374
|
-
opt.lastShownCliInfo = cliInfo
|
|
375
|
-
}
|
|
376
|
-
if (res.status === 504 && !isRetrying) {
|
|
377
|
-
return setTimeout(() => send(d, so, clb, true), 3000)
|
|
378
|
-
}
|
|
379
|
-
if (res.status >= 300 && res.status !== 412) {
|
|
380
|
-
if (obj && (obj.errorMessage || obj.message)) {
|
|
381
|
-
return clb(new Error((obj.errorMessage || obj.message)))
|
|
382
|
-
}
|
|
383
|
-
return clb(new Error(res.statusText + ' (' + res.status + ')'))
|
|
384
|
-
}
|
|
385
|
-
setTimeout(() => clb(null), 1000)
|
|
386
|
-
})
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
if (keysToSend > payloadKeysLimit) {
|
|
390
|
-
const tasks = []
|
|
391
|
-
const keysInObj = Object.keys(data)
|
|
392
|
-
|
|
393
|
-
while (keysInObj.length > payloadKeysLimit) {
|
|
394
|
-
(function () {
|
|
395
|
-
const pagedData = {}
|
|
396
|
-
keysInObj.splice(0, payloadKeysLimit).forEach((k) => { pagedData[k] = data[k] })
|
|
397
|
-
const hasMoreKeys = keysInObj.length > 0
|
|
398
|
-
tasks.push((c) => send(pagedData, hasMoreKeys ? true : shouldOmit, c))
|
|
399
|
-
})()
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (keysInObj.length === 0) return cb(null)
|
|
403
|
-
|
|
404
|
-
const finalPagedData = {}
|
|
405
|
-
keysInObj.splice(0, keysInObj.length).forEach((k) => { finalPagedData[k] = data[k] })
|
|
406
|
-
tasks.push((c) => send(finalPagedData, shouldOmit, c))
|
|
407
|
-
|
|
408
|
-
async.series(tasks, cb)
|
|
409
|
-
return
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
send(data, shouldOmit, cb)
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
const doesDirectoryExist = (p) => {
|
|
416
|
-
let directoryExists = false
|
|
417
|
-
try {
|
|
418
|
-
directoryExists = fs.statSync(p).isDirectory()
|
|
419
|
-
} catch (e) {}
|
|
420
|
-
return directoryExists
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
const cleanupLanguages = (opt, remoteLanguages) => {
|
|
424
|
-
if (opt.pathMask.lastIndexOf(path.sep) < 0) return
|
|
425
|
-
const dirs = getDirectories(opt.path).filter((dir) => dir.indexOf('.') !== 0)
|
|
426
|
-
if (!opt.language && (!opt.languages || opt.languages.length === 0) && !opt.namespace && !opt.namespaces) {
|
|
427
|
-
dirs
|
|
428
|
-
.filter((lng) => {
|
|
429
|
-
const lMask = `${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`
|
|
430
|
-
const startLIndex = opt.pathMask.indexOf(lMask)
|
|
431
|
-
const restLMask = lng.substring((startLIndex || 0) + lMask.length)
|
|
432
|
-
lng = lng.substring(startLIndex || 0, lng.lastIndexOf(restLMask))
|
|
433
|
-
|
|
434
|
-
return lng !== opt.referenceLanguage &&
|
|
435
|
-
!!lngCodes.find((c) => lng === c || lng.indexOf(c + '-') === 0)
|
|
436
|
-
})
|
|
437
|
-
.forEach((lng) => {
|
|
438
|
-
const filledLngMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, lng)
|
|
439
|
-
let lngPath
|
|
440
|
-
if (filledLngMask.lastIndexOf(path.sep) > 0) {
|
|
441
|
-
lngPath = filledLngMask.substring(0, filledLngMask.lastIndexOf(path.sep))
|
|
442
|
-
}
|
|
443
|
-
if (doesDirectoryExist(path.join(opt.path, lngPath, 'CVS'))) return // special hack for CVS
|
|
444
|
-
rimraf.sync(path.join(opt.path, lngPath))
|
|
445
|
-
})
|
|
446
|
-
}
|
|
447
|
-
remoteLanguages.forEach((lng) => {
|
|
448
|
-
if (opt.language && opt.language !== lng) return
|
|
449
|
-
if (opt.languages && opt.languages.length > 0 && opt.languages.indexOf(lng) < 0) return
|
|
450
|
-
const filledLngMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, lng)
|
|
451
|
-
let lngPath
|
|
452
|
-
if (filledLngMask.lastIndexOf(path.sep) > 0) {
|
|
453
|
-
lngPath = filledLngMask.substring(0, filledLngMask.lastIndexOf(path.sep))
|
|
454
|
-
}
|
|
455
|
-
if (lngPath && lngPath.indexOf(`${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`) < 0) mkdirp.sync(path.join(opt.path, lngPath))
|
|
456
|
-
})
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
const handleError = (err, cb) => {
|
|
460
|
-
if (!cb && err) {
|
|
461
|
-
console.error(colors.red(err.stack))
|
|
462
|
-
process.exit(1)
|
|
463
|
-
}
|
|
464
|
-
if (cb) cb(err)
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
const checkForMissingLocalNamespaces = (downloads, localNamespaces, opt) => {
|
|
468
|
-
const localMissingNamespaces = []
|
|
469
|
-
downloads.forEach((d) => {
|
|
470
|
-
const splitted = d.url.split('/')
|
|
471
|
-
const namespace = splitted.pop()
|
|
472
|
-
const language = splitted.pop()
|
|
473
|
-
// if (!opt.referenceLanguageOnly || (opt.referenceLanguageOnly && language === opt.referenceLanguage)) {
|
|
474
|
-
if (language === opt.referenceLanguage) {
|
|
475
|
-
const foundLocalNamespace = localNamespaces.find((n) => n.namespace === namespace && n.language === language)
|
|
476
|
-
if (!foundLocalNamespace) {
|
|
477
|
-
localMissingNamespaces.push({
|
|
478
|
-
language,
|
|
479
|
-
namespace
|
|
480
|
-
})
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
})
|
|
484
|
-
return localMissingNamespaces
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
const backupDeleted = (opt, ns, now) => {
|
|
488
|
-
if (opt.dry || ns.diff.toRemove.length === 0) return
|
|
489
|
-
let m = now.getMonth() + 1
|
|
490
|
-
if (m < 10) m = `0${m}`
|
|
491
|
-
let d = now.getDate()
|
|
492
|
-
if (d < 10) d = `0${d}`
|
|
493
|
-
let h = now.getHours()
|
|
494
|
-
if (h < 10) h = `0${h}`
|
|
495
|
-
let mi = now.getMinutes()
|
|
496
|
-
if (mi < 10) mi = `0${mi}`
|
|
497
|
-
let s = now.getSeconds()
|
|
498
|
-
if (s < 10) s = `0${s}`
|
|
499
|
-
const currentBackupPath = path.join(opt.backupDeletedPath, `${now.getFullYear()}${m}${d}-${h}${mi}${s}`)
|
|
500
|
-
mkdirp.sync(currentBackupPath)
|
|
501
|
-
const removingRemote = ns.diff.toRemove.reduce((prev, k) => {
|
|
502
|
-
prev[k] = ns.remoteContent[k]
|
|
503
|
-
return prev
|
|
504
|
-
}, {})
|
|
505
|
-
mkdirp.sync(path.join(currentBackupPath, ns.language))
|
|
506
|
-
const content = JSON.stringify(removingRemote, null, 2)
|
|
507
|
-
const fileContent = (opt.format !== 'xlsx' && !content.endsWith('\n')) ? (content + '\n') : content
|
|
508
|
-
fs.writeFileSync(path.join(currentBackupPath, ns.language, `${ns.namespace}.json`), fileContent)
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
const handleSync = (opt, remoteLanguages, localNamespaces, cb) => {
|
|
512
|
-
if (!localNamespaces || localNamespaces.length === 0) {
|
|
513
|
-
downloadAll(opt, remoteLanguages, (err) => {
|
|
514
|
-
if (err) return handleError(err, cb)
|
|
515
|
-
if (!cb) console.log(colors.green('FINISHED'))
|
|
516
|
-
if (cb) cb(null)
|
|
517
|
-
})
|
|
518
|
-
return
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
getDownloads(opt, (err, downloads) => {
|
|
522
|
-
if (err) return handleError(err, cb)
|
|
523
|
-
|
|
524
|
-
opt.isPrivate = downloads.length > 0 && downloads[0].isPrivate
|
|
525
|
-
|
|
526
|
-
const localMissingNamespaces = checkForMissingLocalNamespaces(downloads, localNamespaces, opt)
|
|
527
|
-
|
|
528
|
-
compareNamespaces(opt, localNamespaces, (err, compared) => {
|
|
529
|
-
if (err) return handleError(err, cb)
|
|
530
|
-
|
|
531
|
-
const onlyToUpdate = compared.filter((ns) => ns.diff.toAdd.concat(opt.skipDelete ? [] : ns.diff.toRemove).concat(ns.diff.toUpdate).length > 0)
|
|
532
|
-
|
|
533
|
-
const lngsInReqs = []
|
|
534
|
-
const nsInReqs = []
|
|
535
|
-
onlyToUpdate.forEach((n) => {
|
|
536
|
-
if (lngsInReqs.indexOf(n.language) < 0) {
|
|
537
|
-
lngsInReqs.push(n.language)
|
|
538
|
-
}
|
|
539
|
-
if (nsInReqs.indexOf(n.namespace) < 0) {
|
|
540
|
-
nsInReqs.push(n.namespace)
|
|
541
|
-
}
|
|
542
|
-
})
|
|
543
|
-
const shouldOmit = lngsInReqs.length > 5 || nsInReqs.length > 5
|
|
544
|
-
|
|
545
|
-
let wasThereSomethingToUpdate = opt.autoTranslate || false
|
|
546
|
-
|
|
547
|
-
function updateComparedNamespaces () {
|
|
548
|
-
const now = new Date()
|
|
549
|
-
async.eachLimit(compared, Math.round(require('os').cpus().length / 2), (ns, clb) => {
|
|
550
|
-
if (!cb) {
|
|
551
|
-
if (ns.diff.toRemove.length > 0) {
|
|
552
|
-
if (opt.skipDelete) {
|
|
553
|
-
console.log(colors.bgRed(`skipping the removal of ${ns.diff.toRemove.length} keys in ${ns.language}/${ns.namespace}...`))
|
|
554
|
-
if (opt.dry) console.log(colors.bgRed(`skipped to remove ${ns.diff.toRemove.join(', ')} in ${ns.language}/${ns.namespace}...`))
|
|
555
|
-
} else {
|
|
556
|
-
console.log(colors.red(`removing ${ns.diff.toRemove.length} keys in ${ns.language}/${ns.namespace}...`))
|
|
557
|
-
if (opt.dry) console.log(colors.red(`would remove ${ns.diff.toRemove.join(', ')} in ${ns.language}/${ns.namespace}...`))
|
|
558
|
-
if (!opt.dry && opt.backupDeletedPath) backupDeleted(opt, ns, now)
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
if (ns.diff.toRemoveLocally.length > 0) {
|
|
562
|
-
console.log(colors.red(`removing ${ns.diff.toRemoveLocally.length} keys in ${ns.language}/${ns.namespace} locally...`))
|
|
563
|
-
if (opt.dry) console.log(colors.red(`would remove ${ns.diff.toRemoveLocally.join(', ')} in ${ns.language}/${ns.namespace} locally...`))
|
|
564
|
-
}
|
|
565
|
-
if (ns.diff.toAdd.length > 0) {
|
|
566
|
-
console.log(colors.green(`adding ${ns.diff.toAdd.length} keys in ${ns.language}/${ns.namespace}...`))
|
|
567
|
-
if (opt.dry) console.log(colors.green(`would add ${ns.diff.toAdd.join(', ')} in ${ns.language}/${ns.namespace}...`))
|
|
568
|
-
}
|
|
569
|
-
if (ns.diff.toAddLocally.length > 0) {
|
|
570
|
-
if (opt.skipDelete) {
|
|
571
|
-
console.log(colors.bgGreen(`skipping the addition of ${ns.diff.toAddLocally.length} keys in ${ns.language}/${ns.namespace} locally...`))
|
|
572
|
-
if (opt.dry) console.log(colors.bgGreen(`skipped the addition of ${ns.diff.toAddLocally.join(', ')} in ${ns.language}/${ns.namespace} locally...`))
|
|
573
|
-
} else {
|
|
574
|
-
console.log(colors.green(`adding ${ns.diff.toAddLocally.length} keys in ${ns.language}/${ns.namespace} locally...`))
|
|
575
|
-
if (opt.dry) console.log(colors.green(`would add ${ns.diff.toAddLocally.join(', ')} in ${ns.language}/${ns.namespace} locally...`))
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
if (opt.updateValues) {
|
|
579
|
-
if (ns.diff.toUpdate.length > 0) {
|
|
580
|
-
console.log(colors.yellow(`updating ${ns.diff.toUpdate.length} keys in ${ns.language}/${ns.namespace}${opt.autoTranslate ? ' with automatic translation' : ''}...`))
|
|
581
|
-
if (opt.dry) console.log(colors.yellow(`would update ${ns.diff.toUpdate.join(', ')} in ${ns.language}/${ns.namespace}...`))
|
|
582
|
-
}
|
|
583
|
-
if (ns.diff.toUpdateLocally.length > 0) {
|
|
584
|
-
console.log(colors.yellow(`updating ${ns.diff.toUpdateLocally.length} keys in ${ns.language}/${ns.namespace} locally...`))
|
|
585
|
-
if (opt.dry) console.log(colors.yellow(`would update ${ns.diff.toUpdateLocally.join(', ')} in ${ns.language}/${ns.namespace} locally...`))
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
const somethingToUpdate = ns.diff.toAdd.concat(opt.skipDelete ? [] : ns.diff.toRemove)/* .concat(ns.diff.toUpdate) */.length > 0
|
|
589
|
-
if (!somethingToUpdate) console.log(colors.grey(`nothing to update for ${ns.language}/${ns.namespace}`))
|
|
590
|
-
if (!wasThereSomethingToUpdate && somethingToUpdate) wasThereSomethingToUpdate = true
|
|
591
|
-
}
|
|
592
|
-
update(opt, ns.language, ns, shouldOmit, (err) => {
|
|
593
|
-
if (err) return clb(err)
|
|
594
|
-
if (ns.diff.toRemove.length === 0 || ns.language !== opt.referenceLanguage) return clb()
|
|
595
|
-
const nsOnlyRemove = cloneDeep(ns)
|
|
596
|
-
nsOnlyRemove.diff.toAdd = []
|
|
597
|
-
nsOnlyRemove.diff.toUpdate = []
|
|
598
|
-
async.eachLimit(remoteLanguages, Math.round(require('os').cpus().length / 2), (lng, clb) => update(opt, lng, nsOnlyRemove, shouldOmit, clb), clb)
|
|
599
|
-
})
|
|
600
|
-
}, (err) => {
|
|
601
|
-
if (err) return handleError(err, cb)
|
|
602
|
-
if (!cb) console.log(colors.grey('syncing...'))
|
|
603
|
-
|
|
604
|
-
function down () {
|
|
605
|
-
setTimeout(() => { // wait a bit before downloading... just to have a chance to get the newly published files
|
|
606
|
-
downloadAll(opt, remoteLanguages, false, opt.skipDelete
|
|
607
|
-
? (lng, namespace, ns) => {
|
|
608
|
-
const found = compared.find((n) => n.namespace === namespace && n.language === lng)
|
|
609
|
-
if (found && found.diff) {
|
|
610
|
-
if (found.diff.toAddLocally && found.diff.toAddLocally.length > 0) {
|
|
611
|
-
found.diff.toAddLocally.forEach((k) => {
|
|
612
|
-
delete ns[k]
|
|
613
|
-
})
|
|
614
|
-
}
|
|
615
|
-
if (found.diff.toRemove && found.diff.toRemove.length > 0) {
|
|
616
|
-
found.diff.toRemove.forEach((k) => {
|
|
617
|
-
delete ns[k]
|
|
618
|
-
})
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
: undefined, (err) => {
|
|
623
|
-
if (err) return handleError(err, cb)
|
|
624
|
-
if (!cb) console.log(colors.green('FINISHED'))
|
|
625
|
-
if (cb) cb(null)
|
|
626
|
-
})
|
|
627
|
-
}, wasThereSomethingToUpdate && !opt.dry ? (opt.autoTranslate ? 10000 : 5000) : 0)
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
if (!shouldOmit) return down()
|
|
631
|
-
if (opt.dry) return down()
|
|
632
|
-
|
|
633
|
-
// optimize stats generation...
|
|
634
|
-
request(opt.apiEndpoint + '/stats/project/regenerate/' + opt.projectId + '/' + opt.version + (lngsInReqs.length === 1 ? `/${lngsInReqs[0]}` : '') + (nsInReqs.length === 1 ? `?namespace=${nsInReqs[0]}` : ''), {
|
|
635
|
-
method: 'post',
|
|
636
|
-
body: {},
|
|
637
|
-
headers: {
|
|
638
|
-
Authorization: opt.apiKey
|
|
639
|
-
}
|
|
640
|
-
}, (err, res, obj) => {
|
|
641
|
-
if (err) return handleError(err, cb)
|
|
642
|
-
if (res.status >= 300 && res.status !== 412) {
|
|
643
|
-
if (obj && (obj.errorMessage || obj.message)) {
|
|
644
|
-
return handleError(new Error((obj.errorMessage || obj.message)), cb)
|
|
645
|
-
}
|
|
646
|
-
return handleError(new Error(res.statusText + ' (' + res.status + ')'), cb)
|
|
647
|
-
}
|
|
648
|
-
down()
|
|
649
|
-
})
|
|
650
|
-
})
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
if (opt.deleteRemoteNamespace && localMissingNamespaces.length > 0) {
|
|
654
|
-
wasThereSomethingToUpdate = true
|
|
655
|
-
async.eachLimit(localMissingNamespaces, 20, (n, clb) => {
|
|
656
|
-
if (opt.dry) {
|
|
657
|
-
console.log(colors.red(`would delete complete namespace ${n.namespace}...`))
|
|
658
|
-
return clb()
|
|
659
|
-
}
|
|
660
|
-
console.log(colors.red(`deleting complete namespace ${n.namespace}...`))
|
|
661
|
-
deleteNamespace({
|
|
662
|
-
apiEndpoint: opt.apiEndpoint,
|
|
663
|
-
apiKey: opt.apiKey,
|
|
664
|
-
projectId: opt.projectId,
|
|
665
|
-
version: opt.version,
|
|
666
|
-
namespace: n.namespace
|
|
667
|
-
}, clb)
|
|
668
|
-
}, (err) => {
|
|
669
|
-
if (err) return handleError(err, cb)
|
|
670
|
-
updateComparedNamespaces()
|
|
671
|
-
})
|
|
672
|
-
return
|
|
673
|
-
}
|
|
674
|
-
updateComparedNamespaces()
|
|
675
|
-
})
|
|
676
|
-
})
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
const continueToSync = (opt, cb) => {
|
|
680
|
-
console.log(colors.grey('checking remote (locize)...'))
|
|
681
|
-
getRemoteLanguages(opt, (err, remoteLanguages) => {
|
|
682
|
-
if (err) return handleError(err, cb)
|
|
683
|
-
|
|
684
|
-
if (opt.referenceLanguageOnly && opt.language && opt.referenceLanguage !== opt.language) {
|
|
685
|
-
opt.referenceLanguage = opt.language
|
|
686
|
-
}
|
|
687
|
-
if (opt.referenceLanguageOnly && !opt.language && opt.languages && opt.languages.length > 0 && opt.languages.indexOf(opt.referenceLanguage) < 0) {
|
|
688
|
-
opt.referenceLanguage = opt.languages[0]
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
if (opt.referenceLanguageOnly) {
|
|
692
|
-
console.log(colors.grey(`checking local${opt.path !== process.cwd() ? ` (${opt.path})` : ''} only reference language...`))
|
|
693
|
-
parseLocalReference(opt, (err, localNamespaces) => {
|
|
694
|
-
if (err) return handleError(err, cb)
|
|
695
|
-
|
|
696
|
-
if (!opt.dry && opt.cleanLocalFiles) {
|
|
697
|
-
localNamespaces.forEach((ln) => fs.unlinkSync(ln.path))
|
|
698
|
-
localNamespaces = []
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
console.log(colors.grey('calculate diffs...'))
|
|
702
|
-
handleSync(opt, remoteLanguages, localNamespaces, cb)
|
|
703
|
-
})
|
|
704
|
-
return
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
console.log(colors.grey(`checking local${opt.path !== process.cwd() ? ` (${opt.path})` : ''}...`))
|
|
708
|
-
parseLocalLanguages(opt, remoteLanguages, (err, localNamespaces) => {
|
|
709
|
-
if (err) return handleError(err, cb)
|
|
710
|
-
|
|
711
|
-
if (!opt.dry && opt.cleanLocalFiles) {
|
|
712
|
-
localNamespaces.forEach((ln) => fs.unlinkSync(ln.path))
|
|
713
|
-
localNamespaces = []
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
console.log(colors.grey('calculate diffs...'))
|
|
717
|
-
handleSync(opt, remoteLanguages, localNamespaces, cb)
|
|
718
|
-
})
|
|
719
|
-
})
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
const sync = (opt, cb) => {
|
|
723
|
-
opt.format = opt.format || 'json'
|
|
724
|
-
if (!reversedFileExtensionsMap[opt.format]) {
|
|
725
|
-
return handleError(new Error(`${opt.format} is not a valid format!`), cb)
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
if (opt.autoTranslate && !opt.referenceLanguageOnly) {
|
|
729
|
-
console.log(colors.yellow('Using the "--auto-translate true" option together with the "--reference-language-only false" option might result in inconsistent target language translations (automatic translation vs. what is sent direcly to locize).'))
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
opt.version = opt.version || 'latest'
|
|
733
|
-
opt.apiEndpoint = opt.apiEndpoint || 'https://api.locize.app'
|
|
734
|
-
|
|
735
|
-
if (!opt.dry && opt.clean) rimraf.sync(path.join(opt.path, '*'))
|
|
736
|
-
|
|
737
|
-
if (opt.autoCreatePath === false) {
|
|
738
|
-
if (!doesDirectoryExist(opt.path)) {
|
|
739
|
-
return handleError(new Error(`${opt.path} does not exist!`), cb)
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
if (!opt.dry) mkdirp.sync(opt.path)
|
|
743
|
-
|
|
744
|
-
if (opt.namespace && opt.namespace.indexOf(',') > 0 && opt.namespace.indexOf(' ') < 0) {
|
|
745
|
-
opt.namespaces = opt.namespace.split(',')
|
|
746
|
-
delete opt.namespace
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
opt.pathMaskInterpolationPrefix = opt.pathMaskInterpolationPrefix || '{{'
|
|
750
|
-
opt.pathMaskInterpolationSuffix = opt.pathMaskInterpolationSuffix || '}}'
|
|
751
|
-
opt.pathMask = opt.pathMask || `${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}${path.sep}${opt.pathMaskInterpolationPrefix}namespace${opt.pathMaskInterpolationSuffix}`
|
|
752
|
-
opt.languageFolderPrefix = opt.languageFolderPrefix || ''
|
|
753
|
-
opt.pathMask = opt.pathMask.replace(`${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`, `${opt.languageFolderPrefix}${opt.pathMaskInterpolationPrefix}language${opt.pathMaskInterpolationSuffix}`)
|
|
754
|
-
if (opt.overriddenOnly) {
|
|
755
|
-
opt.unpublished = true
|
|
756
|
-
}
|
|
757
|
-
if (opt.unpublished && !opt.apiKey) {
|
|
758
|
-
return handleError(new Error('Please provide also an api-key!'), cb)
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
if (opt.branch === '') {
|
|
762
|
-
return handleError(new Error('The branch name seems invalid!'), cb)
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
if (opt.branch) {
|
|
766
|
-
getBranches(opt, (err, branches) => {
|
|
767
|
-
if (err) return handleError(err, cb)
|
|
768
|
-
|
|
769
|
-
let b
|
|
770
|
-
if (isValidUuid(opt.branch)) b = branches.find((br) => br.id === opt.branch)
|
|
771
|
-
if (!b) b = branches.find((br) => br.name === opt.branch)
|
|
772
|
-
if (!b) {
|
|
773
|
-
return handleError(new Error(`Branch ${opt.branch} not found!`), cb)
|
|
774
|
-
}
|
|
775
|
-
opt.projectId = b.id
|
|
776
|
-
opt.version = b.version
|
|
777
|
-
|
|
778
|
-
continueToSync(opt, cb)
|
|
779
|
-
})
|
|
780
|
-
return
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
continueToSync(opt, cb)
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
module.exports = sync
|