@transifex/cli 4.3.0 → 5.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/README.md +82 -25
- package/bin/run +3 -3
- package/oclif.manifest.json +1 -1
- package/package.json +17 -19
- package/src/api/download.js +83 -0
- package/src/api/extract.js +7 -0
- package/src/api/parsers/txnativejson.js +41 -0
- package/src/api/parsers/vue.js +18 -15
- package/src/api/upload.js +1 -0
- package/src/api/utils.js +15 -0
- package/src/commands/invalidate.js +14 -14
- package/src/commands/pull.js +142 -0
- package/src/commands/push.js +38 -29
- package/src/index.js +3 -1
package/README.md
CHANGED
|
@@ -78,6 +78,7 @@ $ npm run push
|
|
|
78
78
|
# Commands
|
|
79
79
|
* [`txjs-cli help [COMMAND]`](#txjs-cli-help-command)
|
|
80
80
|
* [`txjs-cli push [PATTERN]`](#txjs-cli-push-pattern)
|
|
81
|
+
* [`txjs-cli pull [PATTERN]`](#txjs-cli-pull-pattern)
|
|
81
82
|
* [`txjs-cli invalidate`](#txjs-cli-invalidate)
|
|
82
83
|
|
|
83
84
|
## `txjs-cli help [COMMAND]`
|
|
@@ -101,27 +102,32 @@ detect and push source content to Transifex
|
|
|
101
102
|
|
|
102
103
|
```
|
|
103
104
|
USAGE
|
|
104
|
-
$ txjs-cli push [PATTERN]
|
|
105
|
+
$ txjs-cli push [PATTERN] [--dry-run] [--fake] [-v] [--purge] [--no-wait] [--token <value>] [--secret <value>] [--append-tags <value>] [--with-tags-only <value>] [--without-tags-only <value>]
|
|
106
|
+
[--cds-host <value>] [--parser auto|i18next|txnativejson] [--key-generator source|hash]
|
|
105
107
|
|
|
106
108
|
ARGUMENTS
|
|
107
|
-
PATTERN [default: **/*.{js,jsx,ts,tsx,vue}] file pattern to scan for strings
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
-v, --verbose
|
|
111
|
-
--append-tags
|
|
112
|
-
--cds-host
|
|
113
|
-
--dry-run
|
|
114
|
-
--
|
|
115
|
-
--
|
|
116
|
-
|
|
117
|
-
--
|
|
118
|
-
--
|
|
119
|
-
|
|
120
|
-
--
|
|
121
|
-
--
|
|
109
|
+
PATTERN [default: **/*.{js,jsx,ts,tsx,html,vue,pug,ejs}] file pattern to scan for strings
|
|
110
|
+
|
|
111
|
+
FLAGS
|
|
112
|
+
-v, --verbose verbose output
|
|
113
|
+
--append-tags=<value> append tags to strings
|
|
114
|
+
--cds-host=<value> CDS host URL
|
|
115
|
+
--dry-run dry run, do not apply changes in Transifex
|
|
116
|
+
--fake do not push content to remote server
|
|
117
|
+
--key-generator=<option> [default: source] use hashed or source based keys
|
|
118
|
+
<options: source|hash>
|
|
119
|
+
--no-wait disable polling for upload results
|
|
120
|
+
--parser=<option> [default: auto] file parser to use
|
|
121
|
+
<options: auto|i18next|txnativejson>
|
|
122
|
+
--purge purge content on Transifex
|
|
123
|
+
--secret=<value> native project secret
|
|
124
|
+
--token=<value> native project public token
|
|
125
|
+
--with-tags-only=<value> push strings with specific tags
|
|
126
|
+
--without-tags-only=<value> push strings without specific tags
|
|
122
127
|
|
|
123
128
|
DESCRIPTION
|
|
124
|
-
|
|
129
|
+
Detect and push source content to Transifex
|
|
130
|
+
Parse .js, .ts, .jsx, .tsx and .html files and detect phrases marked for
|
|
125
131
|
translation by Transifex Native toolkit for Javascript and
|
|
126
132
|
upload them to Transifex for translation.
|
|
127
133
|
|
|
@@ -140,6 +146,7 @@ DESCRIPTION
|
|
|
140
146
|
txjs-cli push /home/repo/src
|
|
141
147
|
txjs-cli push "*.js"
|
|
142
148
|
txjs-cli push --dry-run
|
|
149
|
+
txjs-cli push --fake -v
|
|
143
150
|
txjs-cli push --no-wait
|
|
144
151
|
txjs-cli push --key-generator=hash
|
|
145
152
|
txjs-cli push --append-tags="master,release:2.5"
|
|
@@ -147,29 +154,79 @@ DESCRIPTION
|
|
|
147
154
|
txjs-cli push --without-tags-only="custom"
|
|
148
155
|
txjs-cli push --token=mytoken --secret=mysecret
|
|
149
156
|
txjs-cli push en.json --parser=i18next
|
|
157
|
+
txjs-cli push en.json --parser=txnativejson
|
|
150
158
|
TRANSIFEX_TOKEN=mytoken TRANSIFEX_SECRET=mysecret txjs-cli push
|
|
151
159
|
```
|
|
152
160
|
|
|
161
|
+
## `txjs-cli pull [PATTERN]`
|
|
162
|
+
|
|
163
|
+
Pull content from Transifex for offline caching
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
USAGE
|
|
167
|
+
$ txjs-cli pull [--token <value>] [--secret <value>] [-f <value>] [-l <value>] [--pretty] [--filter-tags <value>] [--filter-status reviewed|proofread|finalized] [--cds-host <value>]
|
|
168
|
+
|
|
169
|
+
FLAGS
|
|
170
|
+
-f, --folder=<value> output as files to folder
|
|
171
|
+
-l, --locale=<value> pull specific language locale code
|
|
172
|
+
--cds-host=<value> CDS host URL
|
|
173
|
+
--filter-status=<option> filter over translation status
|
|
174
|
+
<options: reviewed|proofread|finalized>
|
|
175
|
+
--filter-tags=<value> filter over specific tags
|
|
176
|
+
--pretty beautify JSON output
|
|
177
|
+
--secret=<value> native project secret
|
|
178
|
+
--token=<value> native project public token
|
|
179
|
+
|
|
180
|
+
DESCRIPTION
|
|
181
|
+
Pull content from Transifex for offline caching
|
|
182
|
+
Get content as JSON files, to be used by mobile Javascript SDKs for
|
|
183
|
+
offline support or warming up the cache with initial translations.
|
|
184
|
+
|
|
185
|
+
By default, JSON files are printed in the console,
|
|
186
|
+
unless the "-f foldername" parameter is provided. In that case
|
|
187
|
+
the JSON files will be downloaded to that folder with the <locale>.json format.
|
|
188
|
+
|
|
189
|
+
To pull content some environment variables must be set:
|
|
190
|
+
TRANSIFEX_TOKEN=<Transifex Native Project Token>
|
|
191
|
+
TRANSIFEX_SECRET=<Transifex Native Project Secret>
|
|
192
|
+
(optional) TRANSIFEX_CDS_HOST=<CDS HOST>
|
|
193
|
+
|
|
194
|
+
or passed as --token=<TOKEN> --secret=<SECRET> parameters
|
|
195
|
+
|
|
196
|
+
Default CDS Host is https://cds.svc.transifex.net
|
|
197
|
+
|
|
198
|
+
Examples:
|
|
199
|
+
txjs-cli pull
|
|
200
|
+
txjs-cli pull --pretty
|
|
201
|
+
txjs-cli pull -f languages/
|
|
202
|
+
txjs-cli pull --locale=fr -f .
|
|
203
|
+
txjs-cli pull --filter-tags="foo,bar"
|
|
204
|
+
txjs-cli pull --filter-status="reviewed"
|
|
205
|
+
txjs-cli pull --token=mytoken --secret=mysecret
|
|
206
|
+
TRANSIFEX_TOKEN=mytoken TRANSIFEX_SECRET=mysecret txjs-cli pull
|
|
207
|
+
```
|
|
208
|
+
|
|
153
209
|
## `txjs-cli invalidate`
|
|
154
210
|
|
|
155
211
|
invalidate and refresh CDS cache
|
|
156
212
|
|
|
157
213
|
```
|
|
158
214
|
USAGE
|
|
159
|
-
$ txjs-cli invalidate
|
|
215
|
+
$ txjs-cli invalidate [--purge] [--token <value>] [--secret <value>] [--cds-host <value>]
|
|
160
216
|
|
|
161
|
-
|
|
162
|
-
--cds-host
|
|
163
|
-
--purge
|
|
164
|
-
--secret
|
|
165
|
-
--token
|
|
217
|
+
FLAGS
|
|
218
|
+
--cds-host=<value> CDS host URL
|
|
219
|
+
--purge force delete CDS cached content
|
|
220
|
+
--secret=<value> native project secret
|
|
221
|
+
--token=<value> native project public token
|
|
166
222
|
|
|
167
223
|
DESCRIPTION
|
|
224
|
+
Invalidate and refresh CDS cache
|
|
168
225
|
Content for delivery is cached in CDS and refreshed automatically every hour.
|
|
169
226
|
This command triggers a refresh of cached content on the fly.
|
|
170
227
|
|
|
171
|
-
By default, invalidation does not remove existing cached content,
|
|
172
|
-
starts the process of updating with latest translations from Transifex.
|
|
228
|
+
By default, invalidation does not remove existing cached content,
|
|
229
|
+
but starts the process of updating with latest translations from Transifex.
|
|
173
230
|
|
|
174
231
|
Passing the --purge option, cached content will be forced to be deleted,
|
|
175
232
|
however use that with caution, as it may introduce downtime of
|
package/bin/run
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
require('@oclif/
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const oclif = require('@oclif/core');
|
|
4
|
+
|
|
5
|
+
oclif.run().then(require('@oclif/core/flush')).catch(require('@oclif/core/handle'));
|
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"
|
|
1
|
+
{"version":"5.0.0","commands":{"invalidate":{"id":"invalidate","description":"Invalidate and refresh CDS cache\nContent for delivery is cached in CDS and refreshed automatically every hour.\nThis command triggers a refresh of cached content on the fly.\n\nBy default, invalidation does not remove existing cached content,\nbut starts the process of updating with latest translations from Transifex.\n\nPassing the --purge option, cached content will be forced to be deleted,\nhowever use that with caution, as it may introduce downtime of\ntranslation delivery to the apps until fresh content is cached in the CDS.\n\nTo invalidate translations some environment variables must be set:\nTRANSIFEX_TOKEN=<Transifex Native Project Token>\nTRANSIFEX_SECRET=<Transifex Native Project Secret>\n(optional) TRANSIFEX_CDS_HOST=<CDS HOST>\n\nor passed as --token=<TOKEN> --secret=<SECRET> parameters\n\nDefault CDS Host is https://cds.svc.transifex.net\n\nExamples:\ntxjs-cli invalidate\ntxjs-cli invalidate --purge\ntxjs-cli invalidate --token=mytoken --secret=mysecret\nTRANSIFEX_TOKEN=mytoken TRANSIFEX_SECRET=mysecret txjs-cli invalidate\n","pluginName":"@transifex/cli","pluginType":"core","aliases":[],"flags":{"purge":{"name":"purge","type":"boolean","description":"force delete CDS cached content","allowNo":false},"token":{"name":"token","type":"option","description":"native project public token","default":""},"secret":{"name":"secret","type":"option","description":"native project secret","default":""},"cds-host":{"name":"cds-host","type":"option","description":"CDS host URL","default":""}},"args":[]},"pull":{"id":"pull","description":"Pull content from Transifex for offline caching\nGet content as JSON files, to be used by mobile Javascript SDKs for\noffline support or warming up the cache with initial translations.\n\nBy default, JSON files are printed in the console,\nunless the \"-f foldername\" parameter is provided. In that case\nthe JSON files will be downloaded to that folder with the <locale>.json format.\n\nTo pull content some environment variables must be set:\nTRANSIFEX_TOKEN=<Transifex Native Project Token>\nTRANSIFEX_SECRET=<Transifex Native Project Secret>\n(optional) TRANSIFEX_CDS_HOST=<CDS HOST>\n\nor passed as --token=<TOKEN> --secret=<SECRET> parameters\n\nDefault CDS Host is https://cds.svc.transifex.net\n\nExamples:\ntxjs-cli pull\ntxjs-cli pull --pretty\ntxjs-cli pull -f languages/\ntxjs-cli pull --locale=fr -f .\ntxjs-cli pull --filter-tags=\"foo,bar\"\ntxjs-cli pull --filter-status=\"reviewed\"\ntxjs-cli pull --token=mytoken --secret=mysecret\nTRANSIFEX_TOKEN=mytoken TRANSIFEX_SECRET=mysecret txjs-cli pull\n","pluginName":"@transifex/cli","pluginType":"core","aliases":[],"flags":{"token":{"name":"token","type":"option","description":"native project public token","default":""},"secret":{"name":"secret","type":"option","description":"native project secret","default":""},"folder":{"name":"folder","type":"option","char":"f","description":"output as files to folder","default":""},"locale":{"name":"locale","type":"option","char":"l","description":"pull specific language locale code","default":""},"pretty":{"name":"pretty","type":"boolean","description":"beautify JSON output","allowNo":false},"filter-tags":{"name":"filter-tags","type":"option","description":"filter over specific tags","default":""},"filter-status":{"name":"filter-status","type":"option","description":"filter over translation status","options":["reviewed","proofread","finalized"],"default":""},"cds-host":{"name":"cds-host","type":"option","description":"CDS host URL","default":""}},"args":[]},"push":{"id":"push","description":"Detect and push source content to Transifex\nParse .js, .ts, .jsx, .tsx and .html files and detect phrases marked for\ntranslation by Transifex Native toolkit for Javascript and\nupload them to Transifex for translation.\n\nTo push content some environment variables must be set:\nTRANSIFEX_TOKEN=<Transifex Native Project Token>\nTRANSIFEX_SECRET=<Transifex Native Project Secret>\n(optional) TRANSIFEX_CDS_HOST=<CDS HOST>\n\nor passed as --token=<TOKEN> --secret=<SECRET> parameters\n\nDefault CDS Host is https://cds.svc.transifex.net\n\nExamples:\ntxjs-cli push -v\ntxjs-cli push src/\ntxjs-cli push /home/repo/src\ntxjs-cli push \"*.js\"\ntxjs-cli push --dry-run\ntxjs-cli push --fake -v\ntxjs-cli push --no-wait\ntxjs-cli push --key-generator=hash\ntxjs-cli push --append-tags=\"master,release:2.5\"\ntxjs-cli push --with-tags-only=\"home,error\"\ntxjs-cli push --without-tags-only=\"custom\"\ntxjs-cli push --token=mytoken --secret=mysecret\ntxjs-cli push en.json --parser=i18next\ntxjs-cli push en.json --parser=txnativejson\nTRANSIFEX_TOKEN=mytoken TRANSIFEX_SECRET=mysecret txjs-cli push\n","pluginName":"@transifex/cli","pluginType":"core","aliases":[],"flags":{"dry-run":{"name":"dry-run","type":"boolean","description":"dry run, do not apply changes in Transifex","allowNo":false},"fake":{"name":"fake","type":"boolean","description":"do not push content to remote server","allowNo":false},"verbose":{"name":"verbose","type":"boolean","char":"v","description":"verbose output","allowNo":false},"purge":{"name":"purge","type":"boolean","description":"purge content on Transifex","allowNo":false},"no-wait":{"name":"no-wait","type":"boolean","description":"disable polling for upload results","allowNo":false},"token":{"name":"token","type":"option","description":"native project public token","default":""},"secret":{"name":"secret","type":"option","description":"native project secret","default":""},"append-tags":{"name":"append-tags","type":"option","description":"append tags to strings","default":""},"with-tags-only":{"name":"with-tags-only","type":"option","description":"push strings with specific tags","default":""},"without-tags-only":{"name":"without-tags-only","type":"option","description":"push strings without specific tags","default":""},"cds-host":{"name":"cds-host","type":"option","description":"CDS host URL","default":""},"parser":{"name":"parser","type":"option","description":"file parser to use","options":["auto","i18next","txnativejson"],"default":"auto"},"key-generator":{"name":"key-generator","type":"option","description":"use hashed or source based keys","options":["source","hash"],"default":"source"}},"args":[{"name":"pattern","description":"file pattern to scan for strings","required":false,"default":"**/*.{js,jsx,ts,tsx,html,vue,pug,ejs}"}]}}}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transifex/cli",
|
|
3
3
|
"description": "i18n CLI tool for Transifex Native",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "5.0.0",
|
|
5
5
|
"author": "Transifex",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"transifex",
|
|
@@ -24,34 +24,29 @@
|
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@babel/parser": "^7.
|
|
28
|
-
"@babel/traverse": "^7.
|
|
27
|
+
"@babel/parser": "^7.20.3",
|
|
28
|
+
"@babel/traverse": "^7.20.1",
|
|
29
29
|
"@colors/colors": "^1.5.0",
|
|
30
|
-
"@oclif/
|
|
31
|
-
"@
|
|
32
|
-
"@
|
|
33
|
-
"@oclif/plugin-help": "^5.1.12",
|
|
34
|
-
"@transifex/native": "^4.3.0",
|
|
30
|
+
"@oclif/core": "^1.20.4",
|
|
31
|
+
"@transifex/native": "^5.0.0",
|
|
32
|
+
"@vue/compiler-sfc": "^3.2.45",
|
|
35
33
|
"angular-html-parser": "^1.8.0",
|
|
36
|
-
"axios": "^
|
|
37
|
-
"cli-ux": "^6.0.9",
|
|
34
|
+
"axios": "^1.1.3",
|
|
38
35
|
"ejs": "^3.1.8",
|
|
39
36
|
"glob": "^8.0.3",
|
|
40
37
|
"lodash": "^4.17.21",
|
|
41
38
|
"pug": "^3.0.2",
|
|
42
|
-
"shelljs": "^0.8.5"
|
|
43
|
-
"vue-template-compiler": "^2.7.7"
|
|
39
|
+
"shelljs": "^0.8.5"
|
|
44
40
|
},
|
|
45
41
|
"devDependencies": {
|
|
46
42
|
"@oclif/dev-cli": "^1.26.10",
|
|
47
|
-
"@oclif/test": "^2.
|
|
48
|
-
"chai": "^4.3.
|
|
49
|
-
"eslint": "^
|
|
50
|
-
"eslint-config-airbnb-base": "^
|
|
43
|
+
"@oclif/test": "^2.2.12",
|
|
44
|
+
"chai": "^4.3.7",
|
|
45
|
+
"eslint": "^8.28.0",
|
|
46
|
+
"eslint-config-airbnb-base": "^15.0.0",
|
|
51
47
|
"eslint-plugin-import": "^2.26.0",
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"nock": "^13.2.8",
|
|
48
|
+
"mocha": "^10.1.0",
|
|
49
|
+
"nock": "^13.2.9",
|
|
55
50
|
"nyc": "^15.1.0"
|
|
56
51
|
},
|
|
57
52
|
"engines": {
|
|
@@ -66,6 +61,9 @@
|
|
|
66
61
|
"main": "src/index.js",
|
|
67
62
|
"oclif": {
|
|
68
63
|
"commands": "./src/commands",
|
|
64
|
+
"additionalHelpFlags": [
|
|
65
|
+
"-h"
|
|
66
|
+
],
|
|
69
67
|
"bin": "txjs-cli",
|
|
70
68
|
"plugins": [
|
|
71
69
|
"@oclif/plugin-help"
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const { version } = require('../../package.json');
|
|
3
|
+
const { sleep } = require('./utils');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Download languages
|
|
7
|
+
*
|
|
8
|
+
* @param {*} { cdsHost, token, secret }
|
|
9
|
+
* @return {Promise}
|
|
10
|
+
*/
|
|
11
|
+
async function downloadLanguages({ cdsHost, token, secret }) {
|
|
12
|
+
let response;
|
|
13
|
+
let lastResponseStatus = 202;
|
|
14
|
+
while (lastResponseStatus === 202) {
|
|
15
|
+
/* eslint-disable no-await-in-loop */
|
|
16
|
+
response = await axios.get(`${cdsHost}/languages`, {
|
|
17
|
+
headers: {
|
|
18
|
+
Authorization: `Bearer ${token}:${secret}`,
|
|
19
|
+
'Accept-version': 'v2',
|
|
20
|
+
'Content-Type': 'application/json;charset=utf-8',
|
|
21
|
+
'X-NATIVE-SDK': `txjs/cli/${version}`,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
lastResponseStatus = response.status;
|
|
25
|
+
if (lastResponseStatus === 202) {
|
|
26
|
+
await sleep(1000);
|
|
27
|
+
}
|
|
28
|
+
/* eslint-enable no-await-in-loop */
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return response.data;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Download phrases
|
|
36
|
+
*
|
|
37
|
+
* @param {*} {
|
|
38
|
+
* cdsHost, locale, filterTags, filterStatus, token, secret,
|
|
39
|
+
* }
|
|
40
|
+
* @return {Promise}
|
|
41
|
+
*/
|
|
42
|
+
async function downloadPhrases({
|
|
43
|
+
cdsHost, locale, filterTags, filterStatus, token, secret,
|
|
44
|
+
}) {
|
|
45
|
+
let response;
|
|
46
|
+
let lastResponseStatus = 202;
|
|
47
|
+
while (lastResponseStatus === 202) {
|
|
48
|
+
let url = `${cdsHost}/content/${locale}`;
|
|
49
|
+
|
|
50
|
+
const getOptions = [];
|
|
51
|
+
if (filterTags) {
|
|
52
|
+
getOptions.push(`filter[tags]=${filterTags}`);
|
|
53
|
+
}
|
|
54
|
+
if (filterStatus) {
|
|
55
|
+
getOptions.push(`filter[status]=${filterStatus}`);
|
|
56
|
+
}
|
|
57
|
+
if (getOptions.length) {
|
|
58
|
+
url = `${url}?${getOptions.join('&')}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* eslint-disable no-await-in-loop */
|
|
62
|
+
response = await axios.get(url, {
|
|
63
|
+
headers: {
|
|
64
|
+
Authorization: `Bearer ${token}:${secret}`,
|
|
65
|
+
'Accept-version': 'v2',
|
|
66
|
+
'Content-Type': 'application/json;charset=utf-8',
|
|
67
|
+
'X-NATIVE-SDK': `txjs/cli/${version}`,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
lastResponseStatus = response.status;
|
|
71
|
+
if (lastResponseStatus === 202) {
|
|
72
|
+
await sleep(1000);
|
|
73
|
+
}
|
|
74
|
+
/* eslint-enable no-await-in-loop */
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return response.data;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports = {
|
|
81
|
+
downloadPhrases,
|
|
82
|
+
downloadLanguages,
|
|
83
|
+
};
|
package/src/api/extract.js
CHANGED
|
@@ -10,6 +10,7 @@ const { parseHTMLTemplateFile } = require('./parsers/angularHTML');
|
|
|
10
10
|
const { babelExtractPhrases } = require('./parsers/babel');
|
|
11
11
|
const { extractVuePhrases } = require('./parsers/vue');
|
|
12
12
|
const { extractI18NextPhrases } = require('./parsers/i18next');
|
|
13
|
+
const { extractTXNativeJSONPhrases } = require('./parsers/txnativejson');
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Parse file and extract phrases using AST
|
|
@@ -34,6 +35,12 @@ function extractPhrases(file, relativeFile, options = {}) {
|
|
|
34
35
|
return HASHES;
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
// Transifex Native JSON
|
|
39
|
+
if (options.parser === 'txnativejson') {
|
|
40
|
+
extractTXNativeJSONPhrases(HASHES, source, relativeFile, options);
|
|
41
|
+
return HASHES;
|
|
42
|
+
}
|
|
43
|
+
|
|
37
44
|
// PUBG templates
|
|
38
45
|
if (path.extname(file) === '.pug') {
|
|
39
46
|
source = pug.compileClient(source);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const { mergePayload } = require('../merge');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Parse i18next JSON v3 & v4 files
|
|
6
|
+
*
|
|
7
|
+
* @param {Object} HASHES A map of keys and content for phrases
|
|
8
|
+
* @param {String} source The content we want to parse
|
|
9
|
+
* @param {String} relativeFile occurence
|
|
10
|
+
* @param {Object} options
|
|
11
|
+
* @param {String[]} options.appendTags
|
|
12
|
+
* @param {String[]} options.filterWithTags
|
|
13
|
+
* @param {String[]} options.filterWithoutTags
|
|
14
|
+
* @param {Boolean} options.useHashedKeys
|
|
15
|
+
*/
|
|
16
|
+
function extractTXNativeJSONPhrases(HASHES, source, relativeFile, options) {
|
|
17
|
+
let json = {};
|
|
18
|
+
try {
|
|
19
|
+
json = JSON.parse(source);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
_.each(json, (value, key) => {
|
|
24
|
+
mergePayload(HASHES, {
|
|
25
|
+
[key]: value,
|
|
26
|
+
});
|
|
27
|
+
if (options.appendTags) {
|
|
28
|
+
mergePayload(HASHES, {
|
|
29
|
+
[key]: {
|
|
30
|
+
meta: {
|
|
31
|
+
tags: options.appendTags,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
extractTXNativeJSONPhrases,
|
|
41
|
+
};
|
package/src/api/parsers/vue.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
|
-
const vueTemplateCompiler = require('vue-
|
|
2
|
+
const vueTemplateCompiler = require('@vue/compiler-sfc');
|
|
3
3
|
const { createPayload, isPayloadValid } = require('./utils');
|
|
4
4
|
const { mergePayload } = require('../merge');
|
|
5
5
|
const { babelExtractPhrases } = require('./babel');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* A function to traverse the AST provided by the vue-
|
|
8
|
+
* A function to traverse the AST provided by the vue/compiler-sfc package
|
|
9
9
|
*
|
|
10
10
|
* @param {*} ast
|
|
11
11
|
* @param {*} visitor
|
|
@@ -14,7 +14,7 @@ function traverseVueTemplateAst(ast, visitor = {}) {
|
|
|
14
14
|
// Use this in order to identify expressions in the AST since there is no
|
|
15
15
|
// Tag to identify it with when traversing
|
|
16
16
|
const VISITORS = {
|
|
17
|
-
|
|
17
|
+
5: 'Expression',
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
function traverseArray(array, parent) {
|
|
@@ -28,10 +28,13 @@ function traverseVueTemplateAst(ast, visitor = {}) {
|
|
|
28
28
|
if (visitor.enter) visitor.enter(node, parent);
|
|
29
29
|
if (visitor[node.tag]) visitor[node.tag](node, parent);
|
|
30
30
|
// Take care of expressions
|
|
31
|
-
if (visitor[VISITORS[node.type]] && node.
|
|
32
|
-
visitor[VISITORS[node.type]](node, parent);
|
|
31
|
+
if (visitor[VISITORS[node.type]] && node.content) {
|
|
32
|
+
if (node.content.loc.source) visitor[VISITORS[node.type]](node, parent);
|
|
33
33
|
}
|
|
34
34
|
if (node.children) traverseArray(node.children, node);
|
|
35
|
+
if (node.content) {
|
|
36
|
+
if (node.content.children) traverseArray(node.content.children, node);
|
|
37
|
+
}
|
|
35
38
|
if (visitor.exit) visitor.exit(node, parent);
|
|
36
39
|
}
|
|
37
40
|
traverseNode(ast, null);
|
|
@@ -54,11 +57,11 @@ function vueElementVisitor(HASHES, relativeFile, options) {
|
|
|
54
57
|
return (node) => {
|
|
55
58
|
let string;
|
|
56
59
|
const params = {};
|
|
57
|
-
_.each(node.
|
|
60
|
+
_.each(node.props, (attr) => {
|
|
58
61
|
const property = attr.name;
|
|
59
62
|
if (!property || !attr.value) return;
|
|
60
63
|
|
|
61
|
-
const attrValue = attr.value;
|
|
64
|
+
const attrValue = attr.value.content;
|
|
62
65
|
|
|
63
66
|
if (!attrValue) return;
|
|
64
67
|
|
|
@@ -102,25 +105,25 @@ function vueElementVisitor(HASHES, relativeFile, options) {
|
|
|
102
105
|
*/
|
|
103
106
|
function extractVuePhrases(HASHES, source, relativeFile, options) {
|
|
104
107
|
// Use the vue-template-compiler API to parse content
|
|
105
|
-
const vueContent = vueTemplateCompiler.
|
|
106
|
-
|
|
108
|
+
const vueContent = vueTemplateCompiler.parse(source);
|
|
107
109
|
// Get the JS Content from the file and extract hashes/phrases with Babel
|
|
108
|
-
if (vueContent.script && vueContent.script.content) {
|
|
109
|
-
const script = vueContent.script.content;
|
|
110
|
+
if (vueContent.descriptor.script && vueContent.descriptor.script.content) {
|
|
111
|
+
const script = vueContent.descriptor.script.content;
|
|
110
112
|
babelExtractPhrases(HASHES, script, relativeFile, options);
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
// Get the template content from the file and extract hashes/phrases with
|
|
114
116
|
// custom traverse function
|
|
115
|
-
if (vueContent.template && vueContent.template.content) {
|
|
117
|
+
if (vueContent.descriptor.template && vueContent.descriptor.template.content) {
|
|
116
118
|
// Compile to get the AST
|
|
117
|
-
const template = vueTemplateCompiler.
|
|
118
|
-
|
|
119
|
+
const template = vueTemplateCompiler.compileTemplate({
|
|
120
|
+
id: 'sfc-compiler',
|
|
121
|
+
source: vueContent.descriptor.template.content,
|
|
119
122
|
});
|
|
120
123
|
|
|
121
124
|
traverseVueTemplateAst(template.ast, {
|
|
122
125
|
Expression(node) {
|
|
123
|
-
babelExtractPhrases(HASHES, node.
|
|
126
|
+
babelExtractPhrases(HASHES, node.content.loc.source, relativeFile, options);
|
|
124
127
|
},
|
|
125
128
|
T: vueElementVisitor(HASHES, relativeFile, options),
|
|
126
129
|
UT: vueElementVisitor(HASHES, relativeFile, options),
|
package/src/api/upload.js
CHANGED
package/src/api/utils.js
CHANGED
|
@@ -23,7 +23,22 @@ function mergeArrays(array1, array2) {
|
|
|
23
23
|
return _.uniq(_.concat(array1 || [], array2 || []));
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Async/await sleep
|
|
28
|
+
*
|
|
29
|
+
* @param {Number} msec
|
|
30
|
+
* @return {Promise}
|
|
31
|
+
*/
|
|
32
|
+
function sleep(msec) {
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
setTimeout(() => {
|
|
35
|
+
resolve();
|
|
36
|
+
}, msec);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
26
40
|
module.exports = {
|
|
27
41
|
stringToArray,
|
|
28
42
|
mergeArrays,
|
|
43
|
+
sleep,
|
|
29
44
|
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/* eslint no-shadow: 0 */
|
|
2
2
|
|
|
3
3
|
require('@colors/colors');
|
|
4
|
-
const { Command,
|
|
5
|
-
const {
|
|
4
|
+
const { Command, Flags } = require('@oclif/core');
|
|
5
|
+
const { CliUx } = require('@oclif/core');
|
|
6
6
|
const { invalidateCDS } = require('../api/invalidate');
|
|
7
7
|
|
|
8
8
|
class InvalidateCommand extends Command {
|
|
9
9
|
async run() {
|
|
10
|
-
const { flags } = this.parse(InvalidateCommand);
|
|
10
|
+
const { flags } = await this.parse(InvalidateCommand);
|
|
11
11
|
|
|
12
12
|
let cdsHost = process.env.TRANSIFEX_CDS_HOST || 'https://cds.svc.transifex.net';
|
|
13
13
|
let projectToken = process.env.TRANSIFEX_TOKEN;
|
|
@@ -24,9 +24,9 @@ class InvalidateCommand extends Command {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
if (flags.purge) {
|
|
27
|
-
|
|
27
|
+
CliUx.ux.action.start('Invalidating and purging CDS cache', '', { stdout: true });
|
|
28
28
|
} else {
|
|
29
|
-
|
|
29
|
+
CliUx.ux.action.start('Invalidating CDS cache', '', { stdout: true });
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
try {
|
|
@@ -36,22 +36,22 @@ class InvalidateCommand extends Command {
|
|
|
36
36
|
secret: projectSecret,
|
|
37
37
|
purge: flags.purge,
|
|
38
38
|
});
|
|
39
|
-
|
|
39
|
+
CliUx.ux.action.stop('Success'.green);
|
|
40
40
|
this.log(`${(res.data.count || 0).toString().green} records invalidated`);
|
|
41
41
|
this.log('Note: It might take a few minutes for fresh content to be available'.yellow);
|
|
42
42
|
} catch (err) {
|
|
43
|
-
|
|
43
|
+
CliUx.ux.action.stop('Failed'.red);
|
|
44
44
|
this.error(err);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
InvalidateCommand.description = `
|
|
49
|
+
InvalidateCommand.description = `Invalidate and refresh CDS cache
|
|
50
50
|
Content for delivery is cached in CDS and refreshed automatically every hour.
|
|
51
51
|
This command triggers a refresh of cached content on the fly.
|
|
52
52
|
|
|
53
|
-
By default, invalidation does not remove existing cached content,
|
|
54
|
-
starts the process of updating with latest translations from Transifex.
|
|
53
|
+
By default, invalidation does not remove existing cached content,
|
|
54
|
+
but starts the process of updating with latest translations from Transifex.
|
|
55
55
|
|
|
56
56
|
Passing the --purge option, cached content will be forced to be deleted,
|
|
57
57
|
however use that with caution, as it may introduce downtime of
|
|
@@ -76,19 +76,19 @@ TRANSIFEX_TOKEN=mytoken TRANSIFEX_SECRET=mysecret txjs-cli invalidate
|
|
|
76
76
|
InvalidateCommand.args = [];
|
|
77
77
|
|
|
78
78
|
InvalidateCommand.flags = {
|
|
79
|
-
purge:
|
|
79
|
+
purge: Flags.boolean({
|
|
80
80
|
description: 'force delete CDS cached content',
|
|
81
81
|
default: false,
|
|
82
82
|
}),
|
|
83
|
-
token:
|
|
83
|
+
token: Flags.string({
|
|
84
84
|
description: 'native project public token',
|
|
85
85
|
default: '',
|
|
86
86
|
}),
|
|
87
|
-
secret:
|
|
87
|
+
secret: Flags.string({
|
|
88
88
|
description: 'native project secret',
|
|
89
89
|
default: '',
|
|
90
90
|
}),
|
|
91
|
-
'cds-host':
|
|
91
|
+
'cds-host': Flags.string({
|
|
92
92
|
description: 'CDS host URL',
|
|
93
93
|
default: '',
|
|
94
94
|
}),
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/* eslint-disable no-await-in-loop */
|
|
2
|
+
require('@colors/colors');
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { Command, Flags } = require('@oclif/core');
|
|
7
|
+
const { CliUx } = require('@oclif/core');
|
|
8
|
+
const { downloadLanguages, downloadPhrases } = require('../api/download');
|
|
9
|
+
|
|
10
|
+
class PullCommand extends Command {
|
|
11
|
+
async run() {
|
|
12
|
+
const { flags } = await this.parse(PullCommand);
|
|
13
|
+
|
|
14
|
+
let cdsHost = process.env.TRANSIFEX_CDS_HOST || 'https://cds.svc.transifex.net';
|
|
15
|
+
let projectToken = process.env.TRANSIFEX_TOKEN;
|
|
16
|
+
let projectSecret = process.env.TRANSIFEX_SECRET;
|
|
17
|
+
|
|
18
|
+
if (flags.token) projectToken = flags.token;
|
|
19
|
+
if (flags.secret) projectSecret = flags.secret;
|
|
20
|
+
if (flags['cds-host']) cdsHost = flags['cds-host'];
|
|
21
|
+
|
|
22
|
+
if (!projectToken || !projectSecret) {
|
|
23
|
+
this.log(`${'✘'.red} Cannot pull content, credentials are missing.`);
|
|
24
|
+
this.log('Tip: Set TRANSIFEX_TOKEN and TRANSIFEX_SECRET environment variables'.yellow);
|
|
25
|
+
process.exit();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
// get source lang
|
|
30
|
+
const params = {
|
|
31
|
+
cdsHost,
|
|
32
|
+
token: projectToken,
|
|
33
|
+
secret: projectSecret,
|
|
34
|
+
filterTags: flags['filter-tags'],
|
|
35
|
+
filterStatus: flags['filter-status'],
|
|
36
|
+
locale: '',
|
|
37
|
+
};
|
|
38
|
+
const locales = [];
|
|
39
|
+
if (flags.locale) {
|
|
40
|
+
locales.push(flags.locale);
|
|
41
|
+
} else {
|
|
42
|
+
CliUx.ux.action.start('Getting available languages', '', { stdout: true });
|
|
43
|
+
const languages = await downloadLanguages(params);
|
|
44
|
+
_.each(languages.data, (entry) => {
|
|
45
|
+
if (entry.code) {
|
|
46
|
+
locales.push(entry.code);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
for (let i = 0; i < locales.length; i += 1) {
|
|
51
|
+
params.locale = locales[i];
|
|
52
|
+
CliUx.ux.action.start(
|
|
53
|
+
`Pulling content for ${params.locale.green} locale (${i + 1} of ${locales.length})`,
|
|
54
|
+
'',
|
|
55
|
+
{ stdout: true },
|
|
56
|
+
);
|
|
57
|
+
const { data } = await downloadPhrases(params);
|
|
58
|
+
const json = flags.pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
59
|
+
if (flags.folder) {
|
|
60
|
+
fs.writeFileSync(path.join(flags.folder, `${params.locale}.json`), json);
|
|
61
|
+
}
|
|
62
|
+
if (!flags.folder) {
|
|
63
|
+
this.log(json);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
CliUx.ux.action.stop('Done'.green);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
CliUx.ux.action.stop('Failed'.red);
|
|
69
|
+
this.error(err);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
PullCommand.description = `Pull content from Transifex for offline caching
|
|
75
|
+
Get content as JSON files, to be used by mobile Javascript SDKs for
|
|
76
|
+
offline support or warming up the cache with initial translations.
|
|
77
|
+
|
|
78
|
+
By default, JSON files are printed in the console,
|
|
79
|
+
unless the "-f foldername" parameter is provided. In that case
|
|
80
|
+
the JSON files will be downloaded to that folder with the <locale>.json format.
|
|
81
|
+
|
|
82
|
+
To pull content some environment variables must be set:
|
|
83
|
+
TRANSIFEX_TOKEN=<Transifex Native Project Token>
|
|
84
|
+
TRANSIFEX_SECRET=<Transifex Native Project Secret>
|
|
85
|
+
(optional) TRANSIFEX_CDS_HOST=<CDS HOST>
|
|
86
|
+
|
|
87
|
+
or passed as --token=<TOKEN> --secret=<SECRET> parameters
|
|
88
|
+
|
|
89
|
+
Default CDS Host is https://cds.svc.transifex.net
|
|
90
|
+
|
|
91
|
+
Examples:
|
|
92
|
+
txjs-cli pull
|
|
93
|
+
txjs-cli pull --pretty
|
|
94
|
+
txjs-cli pull -f languages/
|
|
95
|
+
txjs-cli pull --locale=fr -f .
|
|
96
|
+
txjs-cli pull --filter-tags="foo,bar"
|
|
97
|
+
txjs-cli pull --filter-status="reviewed"
|
|
98
|
+
txjs-cli pull --token=mytoken --secret=mysecret
|
|
99
|
+
TRANSIFEX_TOKEN=mytoken TRANSIFEX_SECRET=mysecret txjs-cli pull
|
|
100
|
+
`;
|
|
101
|
+
|
|
102
|
+
PullCommand.args = [];
|
|
103
|
+
|
|
104
|
+
PullCommand.flags = {
|
|
105
|
+
token: Flags.string({
|
|
106
|
+
description: 'native project public token',
|
|
107
|
+
default: '',
|
|
108
|
+
}),
|
|
109
|
+
secret: Flags.string({
|
|
110
|
+
description: 'native project secret',
|
|
111
|
+
default: '',
|
|
112
|
+
}),
|
|
113
|
+
folder: Flags.string({
|
|
114
|
+
char: 'f',
|
|
115
|
+
description: 'output as files to folder',
|
|
116
|
+
default: '',
|
|
117
|
+
}),
|
|
118
|
+
locale: Flags.string({
|
|
119
|
+
char: 'l',
|
|
120
|
+
description: 'pull specific language locale code',
|
|
121
|
+
default: '',
|
|
122
|
+
}),
|
|
123
|
+
pretty: Flags.boolean({
|
|
124
|
+
description: 'beautify JSON output',
|
|
125
|
+
default: false,
|
|
126
|
+
}),
|
|
127
|
+
'filter-tags': Flags.string({
|
|
128
|
+
description: 'filter over specific tags',
|
|
129
|
+
default: '',
|
|
130
|
+
}),
|
|
131
|
+
'filter-status': Flags.string({
|
|
132
|
+
description: 'filter over translation status',
|
|
133
|
+
default: '',
|
|
134
|
+
options: ['reviewed', 'proofread', 'finalized'],
|
|
135
|
+
}),
|
|
136
|
+
'cds-host': Flags.string({
|
|
137
|
+
description: 'CDS host URL',
|
|
138
|
+
default: '',
|
|
139
|
+
}),
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
module.exports = PullCommand;
|
package/src/commands/push.js
CHANGED
|
@@ -5,10 +5,10 @@ require('@colors/colors');
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const _ = require('lodash');
|
|
8
|
-
const { Command,
|
|
8
|
+
const { Command, Flags } = require('@oclif/core');
|
|
9
9
|
const shelljs = require('shelljs');
|
|
10
10
|
const { glob } = require('glob');
|
|
11
|
-
const {
|
|
11
|
+
const { CliUx } = require('@oclif/core');
|
|
12
12
|
const { extractPhrases } = require('../api/extract');
|
|
13
13
|
const { uploadPhrases, pollJob } = require('../api/upload');
|
|
14
14
|
const { mergePayload } = require('../api/merge');
|
|
@@ -31,7 +31,7 @@ function isFolder(path) {
|
|
|
31
31
|
|
|
32
32
|
class PushCommand extends Command {
|
|
33
33
|
async run() {
|
|
34
|
-
const { args, flags } = this.parse(PushCommand);
|
|
34
|
+
const { args, flags } = await this.parse(PushCommand);
|
|
35
35
|
const pwd = `${shelljs.pwd()}`;
|
|
36
36
|
let filePattern = path.isAbsolute(args.pattern)
|
|
37
37
|
? args.pattern
|
|
@@ -61,7 +61,7 @@ class PushCommand extends Command {
|
|
|
61
61
|
const payload = {};
|
|
62
62
|
const tree = {};
|
|
63
63
|
|
|
64
|
-
const bar =
|
|
64
|
+
const bar = CliUx.ux.progress({
|
|
65
65
|
format: '⸨{bar}⸩ {value}/{total} {file}',
|
|
66
66
|
barCompleteChar: '\u2588',
|
|
67
67
|
barIncompleteChar: '⠂',
|
|
@@ -137,7 +137,7 @@ class PushCommand extends Command {
|
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
if (!flags
|
|
140
|
+
if (!flags.fake) {
|
|
141
141
|
if (_.isEmpty(payload)) {
|
|
142
142
|
this.log('⚠ Nothing to upload.'.yellow);
|
|
143
143
|
process.exit();
|
|
@@ -157,20 +157,23 @@ class PushCommand extends Command {
|
|
|
157
157
|
process.exit();
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
const uploadMessage = '
|
|
160
|
+
const uploadMessage = flags['dry-run']
|
|
161
|
+
? 'Uploading content to Transifex (dry run, no changes will be applied)'
|
|
162
|
+
: 'Uploading content to Transifex';
|
|
161
163
|
|
|
162
164
|
this.log('');
|
|
163
|
-
|
|
165
|
+
CliUx.ux.action.start(uploadMessage, '', { stdout: true });
|
|
164
166
|
try {
|
|
165
167
|
let res = await uploadPhrases(payload, {
|
|
166
168
|
url: cdsHost,
|
|
167
169
|
token: projectToken,
|
|
168
170
|
secret: projectSecret,
|
|
169
171
|
purge: flags.purge,
|
|
172
|
+
dry_run: flags['dry-run'],
|
|
170
173
|
});
|
|
171
174
|
|
|
172
175
|
if (flags['no-wait']) {
|
|
173
|
-
|
|
176
|
+
CliUx.ux.action.stop('Queued'.green);
|
|
174
177
|
return;
|
|
175
178
|
}
|
|
176
179
|
|
|
@@ -178,7 +181,7 @@ class PushCommand extends Command {
|
|
|
178
181
|
const jobUrl = `${cdsHost}${res.jobUrl}`;
|
|
179
182
|
let status = '';
|
|
180
183
|
do {
|
|
181
|
-
await
|
|
184
|
+
await CliUx.ux.wait(1500);
|
|
182
185
|
res = await pollJob({
|
|
183
186
|
url: jobUrl,
|
|
184
187
|
token: projectToken,
|
|
@@ -188,10 +191,10 @@ class PushCommand extends Command {
|
|
|
188
191
|
status = res.status;
|
|
189
192
|
switch (status) {
|
|
190
193
|
case 'pending':
|
|
191
|
-
|
|
194
|
+
CliUx.ux.action.start(uploadMessage, 'In queue', { stdout: true });
|
|
192
195
|
break;
|
|
193
196
|
case 'processing':
|
|
194
|
-
|
|
197
|
+
CliUx.ux.action.start(uploadMessage, 'Processing', { stdout: true });
|
|
195
198
|
break;
|
|
196
199
|
default:
|
|
197
200
|
break;
|
|
@@ -200,7 +203,7 @@ class PushCommand extends Command {
|
|
|
200
203
|
} while (status === 'pending' || status === 'processing');
|
|
201
204
|
|
|
202
205
|
if (status === 'completed') {
|
|
203
|
-
|
|
206
|
+
CliUx.ux.action.stop('Success'.green);
|
|
204
207
|
this.log(`${'✓'.green} Successfully pushed strings to Transifex:`);
|
|
205
208
|
if (res.created > 0) {
|
|
206
209
|
this.log(` Created strings: ${res.created.toString().green}`);
|
|
@@ -218,20 +221,20 @@ class PushCommand extends Command {
|
|
|
218
221
|
this.log(` Failed strings: ${res.failed.toString().red}`);
|
|
219
222
|
}
|
|
220
223
|
} else {
|
|
221
|
-
|
|
224
|
+
CliUx.ux.action.stop('Failed'.red);
|
|
222
225
|
}
|
|
223
226
|
_.each(res.errors, (error) => {
|
|
224
227
|
this.log(`Error: ${JSON.stringify(error).red}`);
|
|
225
228
|
});
|
|
226
229
|
} catch (err) {
|
|
227
|
-
|
|
230
|
+
CliUx.ux.action.stop('Failed'.red);
|
|
228
231
|
this.error(err);
|
|
229
232
|
}
|
|
230
233
|
}
|
|
231
234
|
}
|
|
232
235
|
}
|
|
233
236
|
|
|
234
|
-
PushCommand.description = `
|
|
237
|
+
PushCommand.description = `Detect and push source content to Transifex
|
|
235
238
|
Parse .js, .ts, .jsx, .tsx and .html files and detect phrases marked for
|
|
236
239
|
translation by Transifex Native toolkit for Javascript and
|
|
237
240
|
upload them to Transifex for translation.
|
|
@@ -251,6 +254,7 @@ txjs-cli push src/
|
|
|
251
254
|
txjs-cli push /home/repo/src
|
|
252
255
|
txjs-cli push "*.js"
|
|
253
256
|
txjs-cli push --dry-run
|
|
257
|
+
txjs-cli push --fake -v
|
|
254
258
|
txjs-cli push --no-wait
|
|
255
259
|
txjs-cli push --key-generator=hash
|
|
256
260
|
txjs-cli push --append-tags="master,release:2.5"
|
|
@@ -258,6 +262,7 @@ txjs-cli push --with-tags-only="home,error"
|
|
|
258
262
|
txjs-cli push --without-tags-only="custom"
|
|
259
263
|
txjs-cli push --token=mytoken --secret=mysecret
|
|
260
264
|
txjs-cli push en.json --parser=i18next
|
|
265
|
+
txjs-cli push en.json --parser=txnativejson
|
|
261
266
|
TRANSIFEX_TOKEN=mytoken TRANSIFEX_SECRET=mysecret txjs-cli push
|
|
262
267
|
`;
|
|
263
268
|
|
|
@@ -269,53 +274,57 @@ PushCommand.args = [{
|
|
|
269
274
|
}];
|
|
270
275
|
|
|
271
276
|
PushCommand.flags = {
|
|
272
|
-
'dry-run':
|
|
273
|
-
description: 'dry run, do not
|
|
277
|
+
'dry-run': Flags.boolean({
|
|
278
|
+
description: 'dry run, do not apply changes in Transifex',
|
|
274
279
|
default: false,
|
|
275
280
|
}),
|
|
276
|
-
|
|
281
|
+
fake: Flags.boolean({
|
|
282
|
+
description: 'do not push content to remote server',
|
|
283
|
+
default: false,
|
|
284
|
+
}),
|
|
285
|
+
verbose: Flags.boolean({
|
|
277
286
|
char: 'v',
|
|
278
287
|
description: 'verbose output',
|
|
279
288
|
default: false,
|
|
280
289
|
}),
|
|
281
|
-
purge:
|
|
290
|
+
purge: Flags.boolean({
|
|
282
291
|
description: 'purge content on Transifex',
|
|
283
292
|
default: false,
|
|
284
293
|
}),
|
|
285
|
-
'no-wait':
|
|
294
|
+
'no-wait': Flags.boolean({
|
|
286
295
|
description: 'disable polling for upload results',
|
|
287
296
|
default: false,
|
|
288
297
|
}),
|
|
289
|
-
token:
|
|
298
|
+
token: Flags.string({
|
|
290
299
|
description: 'native project public token',
|
|
291
300
|
default: '',
|
|
292
301
|
}),
|
|
293
|
-
secret:
|
|
302
|
+
secret: Flags.string({
|
|
294
303
|
description: 'native project secret',
|
|
295
304
|
default: '',
|
|
296
305
|
}),
|
|
297
|
-
'append-tags':
|
|
306
|
+
'append-tags': Flags.string({
|
|
298
307
|
description: 'append tags to strings',
|
|
299
308
|
default: '',
|
|
300
309
|
}),
|
|
301
|
-
'with-tags-only':
|
|
310
|
+
'with-tags-only': Flags.string({
|
|
302
311
|
description: 'push strings with specific tags',
|
|
303
312
|
default: '',
|
|
304
313
|
}),
|
|
305
|
-
'without-tags-only':
|
|
314
|
+
'without-tags-only': Flags.string({
|
|
306
315
|
description: 'push strings without specific tags',
|
|
307
316
|
default: '',
|
|
308
317
|
}),
|
|
309
|
-
'cds-host':
|
|
318
|
+
'cds-host': Flags.string({
|
|
310
319
|
description: 'CDS host URL',
|
|
311
320
|
default: '',
|
|
312
321
|
}),
|
|
313
|
-
parser:
|
|
322
|
+
parser: Flags.string({
|
|
314
323
|
description: 'file parser to use',
|
|
315
324
|
default: 'auto',
|
|
316
|
-
options: ['auto', 'i18next'],
|
|
325
|
+
options: ['auto', 'i18next', 'txnativejson'],
|
|
317
326
|
}),
|
|
318
|
-
'key-generator':
|
|
327
|
+
'key-generator': Flags.string({
|
|
319
328
|
description: 'use hashed or source based keys',
|
|
320
329
|
default: 'source',
|
|
321
330
|
options: ['source', 'hash'],
|
package/src/index.js
CHANGED