@transifex/cli
Advanced tools
Comparing version 0.11.2 to 0.12.1
@@ -1,1 +0,1 @@ | ||
{"version":"0.11.2","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, but\nstarts 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":[]},"push":{"id":"push","description":"detect and push source content to Transifex\nParse .js, .ts, .jsx and .tsx 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 --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\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 push to Transifex","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},"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":""}},"args":[{"name":"pattern","description":"file pattern to scan for strings","required":false,"default":"**/*.{js,jsx,ts,tsx}"}]}}} | ||
{"version":"0.12.1","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, but\nstarts 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":[]},"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 --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\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 push to Transifex","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},"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":""}},"args":[{"name":"pattern","description":"file pattern to scan for strings","required":false,"default":"**/*.{js,jsx,ts,tsx}"}]}}} |
{ | ||
"name": "@transifex/cli", | ||
"description": "Transifex Native CLI", | ||
"version": "0.11.2", | ||
"version": "0.12.1", | ||
"author": "Transifex", | ||
@@ -30,3 +30,4 @@ "keywords": [ | ||
"@oclif/plugin-help": "^3.2.1", | ||
"@transifex/native": "^0.11.2", | ||
"@transifex/native": "^0.12.1", | ||
"angular-html-parser": "^1.7.1", | ||
"axios": "^0.21.1", | ||
@@ -71,4 +72,6 @@ "cli-ux": "^5.5.1", | ||
"prepack": "oclif-dev manifest", | ||
"test": "nyc mocha \"test/**/*.test.js\"" | ||
"lint": "eslint src/", | ||
"test": "nyc mocha \"test/**/*.test.js\"", | ||
"publish-npm": "npm publish" | ||
} | ||
} |
# Transifex Native CLI | ||
A command line tool that parses `.js`, `.ts`, `.jsx` and `.tsx` source files, extracts phrases marked for localization by [Transifex Native](https://www.transifex.com/native/) and pushes them to [Transifex](https:/www.transifex.com) for translation. | ||
A command line tool that parses `.js`, `.ts`, `.jsx`, `.tsx` and `.html` source files, extracts phrases marked for localization by [Transifex Native](https://www.transifex.com/native/) and pushes them to [Transifex](https:/www.transifex.com) for translation. | ||
@@ -5,0 +5,0 @@ Related packages: |
/* eslint no-underscore-dangle: 0 */ | ||
const ngHtmlParser = require('angular-html-parser'); | ||
@@ -7,2 +8,3 @@ const fs = require('fs'); | ||
const _ = require('lodash'); | ||
const path = require('path'); | ||
const { generateKey } = require('@transifex/native'); | ||
@@ -86,2 +88,61 @@ | ||
/** | ||
* Parse an HTML file and detects T/UT tags | ||
* | ||
* @param {Object} HASHES | ||
* @param {String} filename | ||
* @param {String} relativeFile | ||
* @param {String[]} appendTags | ||
* @param {Object} options | ||
* @returns void | ||
*/ | ||
function parseHTMLTemplateFile(HASHES, filename, relativeFile, | ||
appendTags, options) { | ||
const TXComponents = []; | ||
function parseTemplateNode(children) { | ||
if (children) { | ||
_.each(children, (child) => { | ||
if (child.name === 'T' || child.name === 'UT') { | ||
TXComponents.push(child); | ||
} | ||
parseTemplateNode(child.children); | ||
}); | ||
} | ||
} | ||
const data = fs.readFileSync(filename, 'utf8'); | ||
const { rootNodes, errors } = ngHtmlParser.parse(data); | ||
if (errors.length) return; | ||
parseTemplateNode(rootNodes); | ||
_.each(TXComponents, (txcmp) => { | ||
let string = ''; | ||
let key = ''; | ||
const params = {}; | ||
if (txcmp.attrs) { | ||
_.each(txcmp.attrs, (attribute) => { | ||
if (attribute.name === 'str') { | ||
string = attribute.value; | ||
} else if (attribute.name === 'key') { | ||
key = attribute.value; | ||
} else { | ||
params[attribute.name] = attribute.value; | ||
} | ||
}); | ||
} | ||
if (string) { | ||
const partial = createPayload(string, params, relativeFile, appendTags); | ||
if (!isPayloadValid(partial, options)) return; | ||
mergePayload(HASHES, { | ||
[key || partial.key]: { | ||
string: partial.string, | ||
meta: partial.meta, | ||
}, | ||
}); | ||
} | ||
}); | ||
} | ||
function _parse(source) { | ||
@@ -133,2 +194,3 @@ try { | ||
if (node.type === 'VariableDeclarator' && node.init) { | ||
// eslint-disable-next-line no-use-before-define | ||
return findDeclaredValue(scope, node.init); | ||
@@ -188,79 +250,118 @@ } | ||
const source = fs.readFileSync(file, 'utf8'); | ||
const ast = _parse(source); | ||
babelTraverse(ast, { | ||
if (path.extname(file) !== '.html') { | ||
const ast = _parse(source); | ||
babelTraverse(ast, { | ||
// T / UT functions | ||
CallExpression({ node, scope }) { | ||
CallExpression({ node, scope }) { | ||
// Check if node is a Transifex function | ||
if (!isTransifexCall(node)) return; | ||
if (_.isEmpty(node.arguments)) return; | ||
if (!isTransifexCall(node)) return; | ||
if (_.isEmpty(node.arguments)) return; | ||
// Try to find the value of first argument | ||
const string = findDeclaredValue(scope, node.arguments[0]); | ||
// Try to find the value of first argument | ||
const string = findDeclaredValue(scope, node.arguments[0]); | ||
// Verify that at least the string is passed to the function | ||
if (!_.isString(string)) return; | ||
// Verify that at least the string is passed to the function | ||
if (!_.isString(string)) return; | ||
// Extract function parameters | ||
const params = {}; | ||
if ( | ||
node.arguments[1] | ||
// Extract function parameters | ||
const params = {}; | ||
if ( | ||
node.arguments[1] | ||
&& node.arguments[1].type === 'ObjectExpression' | ||
) { | ||
_.each(node.arguments[1].properties, (prop) => { | ||
) { | ||
_.each(node.arguments[1].properties, (prop) => { | ||
// get only string on number params | ||
if (_.isString(prop.value.value) || _.isNumber(prop.value.value)) { | ||
params[prop.key.name] = prop.value.value; | ||
if (_.isString(prop.value.value) || _.isNumber(prop.value.value)) { | ||
params[prop.key.name] = prop.value.value; | ||
} | ||
}); | ||
} | ||
const partial = createPayload(string, params, relativeFile, appendTags); | ||
if (!isPayloadValid(partial, options)) return; | ||
mergePayload(HASHES, { | ||
[partial.key]: { | ||
string: partial.string, | ||
meta: partial.meta, | ||
}, | ||
}); | ||
}, | ||
// Decorator | ||
Decorator({ node }) { | ||
const elem = node.expression; | ||
if (!elem || !elem.arguments || !elem.arguments.length) return; | ||
if (!node.expression.callee.name === 'T') return; | ||
let string = ''; | ||
let key = ''; | ||
const params = {}; | ||
_.each(node.expression.arguments, (arg) => { | ||
if (arg.type === 'StringLiteral') { | ||
string = arg.value; | ||
} else if (arg.type === 'ObjectExpression') { | ||
_.each(arg.properties, (prop) => { | ||
if (prop.key.name === '_key') { | ||
key = prop.value.value; | ||
} else { | ||
params[prop.key.name] = prop.value.value; | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
if (!string) return; | ||
if (string) { | ||
const partial = createPayload(string, params, relativeFile, appendTags); | ||
if (!isPayloadValid(partial, options)) return; | ||
const partial = createPayload(string, params, relativeFile, appendTags); | ||
if (!isPayloadValid(partial, options)) return; | ||
mergePayload(HASHES, { | ||
[key || partial.key]: { | ||
string: partial.string, | ||
meta: partial.meta, | ||
}, | ||
}); | ||
} | ||
}, | ||
mergePayload(HASHES, { | ||
[partial.key]: { | ||
string: partial.string, | ||
meta: partial.meta, | ||
}, | ||
}); | ||
}, | ||
// React component | ||
JSXElement({ node }) { | ||
const elem = node.openingElement; | ||
// React component | ||
JSXElement({ node }) { | ||
const elem = node.openingElement; | ||
if (!elem || !elem.name) return; | ||
if (elem.name.name !== 'T' && elem.name.name !== 'UT') return; | ||
if (!elem || !elem.name) return; | ||
if (elem.name.name !== 'T' && elem.name.name !== 'UT') return; | ||
let string; | ||
const params = {}; | ||
_.each(elem.attributes, (attr) => { | ||
const property = attr.name && attr.name.name; | ||
const value = attr.value && attr.value.value; | ||
if (!property || !value) return; | ||
if (property === '_str') { | ||
string = value; | ||
return; | ||
} | ||
if (_.isString(value) || _.isNumber(value)) { | ||
params[property] = value; | ||
} | ||
}); | ||
let string; | ||
const params = {}; | ||
_.each(elem.attributes, (attr) => { | ||
const property = attr.name && attr.name.name; | ||
const value = attr.value && attr.value.value; | ||
if (!property || !value) return; | ||
if (property === '_str') { | ||
string = value; | ||
return; | ||
} | ||
if (_.isString(value) || _.isNumber(value)) { | ||
params[property] = value; | ||
} | ||
}); | ||
if (!string) return; | ||
if (!string) return; | ||
const partial = createPayload(string, params, relativeFile, appendTags); | ||
if (!isPayloadValid(partial, options)) return; | ||
const partial = createPayload(string, params, relativeFile, appendTags); | ||
if (!isPayloadValid(partial, options)) return; | ||
mergePayload(HASHES, { | ||
[partial.key]: { | ||
string: partial.string, | ||
meta: partial.meta, | ||
}, | ||
}); | ||
}, | ||
}); | ||
} else if (path.extname(file) === '.html') { | ||
parseHTMLTemplateFile(HASHES, file, relativeFile, appendTags, options); | ||
} | ||
mergePayload(HASHES, { | ||
[partial.key]: { | ||
string: partial.string, | ||
meta: partial.meta, | ||
}, | ||
}); | ||
}, | ||
}); | ||
return HASHES; | ||
@@ -267,0 +368,0 @@ } |
@@ -40,3 +40,3 @@ /* eslint no-shadow: 0 */ | ||
if (isFolder(filePattern)) { | ||
filePattern = path.join(filePattern, '**/*.{js,jsx,ts,tsx}'); | ||
filePattern = path.join(filePattern, '**/*.{js,jsx,ts,tsx,html}'); | ||
} | ||
@@ -183,3 +183,3 @@ | ||
PushCommand.description = `detect and push source content to Transifex | ||
Parse .js, .ts, .jsx and .tsx files and detect phrases marked for | ||
Parse .js, .ts, .jsx, .tsx and .html files and detect phrases marked for | ||
translation by Transifex Native toolkit for Javascript and | ||
@@ -186,0 +186,0 @@ upload them to Transifex for translation. |
35666
809
14
+ Addedangular-html-parser@^1.7.1
+ Added@transifex/native@0.12.2(transitive)
+ Addedangular-html-parser@1.8.0(transitive)
+ Addedtslib@1.14.1(transitive)
- Removed@transifex/native@0.11.2(transitive)
Updated@transifex/native@^0.12.1