New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

jsxgettext

Package Overview
Dependencies
Maintainers
7
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jsxgettext - npm Package Compare versions

Comparing version 0.3.4 to 0.3.5

.jshintignore

130

lib/cli.js
#!/usr/bin/env node
"use strict";
var fs = require('fs');
var path = require('path');
var parsers = require('./parsers');
var jsxgettext = require('./jsxgettext');
var opts = require("nomnom")
.script('jsxgettext')
.option('output', {
abbr: 'o',
metavar: 'FILE',
default: 'messages.po',
help: 'write output to specified file'
})
.option('output-dir', {
abbr: 'p',
metavar: 'DIR',
help: 'output files will be placed in directory DIR'
})
.option('version', {
abbr: 'v',
flag: true,
help: 'print version and exit',
callback: function() {
return require('../package.json').version;
}
})
.option('input', {
position: 0,
required: true,
list: true,
help: 'input files'
})
.option('keyword', {
abbr: 'k',
metavar: 'WORD',
help: 'additional keyword to be looked for'
})
.option('join-existing', {
abbr: 'j',
flag: true,
help: 'join messages with existing file'
})
.option('language', {
abbr: 'L',
metavar: 'NAME',
default: 'JavaScript',
help: 'recognise the specified language (JavaScript, EJS, Jinja, Jade, Handlebars)'
})
.parse();
.script('jsxgettext')
.option('output', {
abbr: 'o',
metavar: 'FILE',
default: 'messages.po',
help: 'write output to specified file'
})
.option('output-dir', {
abbr: 'p',
metavar: 'DIR',
help: 'output files will be placed in directory DIR'
})
.option('version', {
abbr: 'v',
flag: true,
help: 'print version and exit',
callback: function () {
return require('../package.json').version;
}
})
.option('input', {
position: 0,
required: true,
list: true,
help: 'input files'
})
.option('keyword', {
abbr: 'k',
metavar: 'WORD',
help: 'additional keyword to be looked for'
})
.option('join-existing', {
abbr: 'j',
flag: true,
help: 'join messages with existing file'
})
.option('language', {
abbr: 'L',
metavar: 'NAME',
default: 'javascript',
help: 'use the specified language (' + ['javascript'].concat(Object.keys(parsers)).join(', ') + ')'
})
.parse();
function main () {
function gen(sources) {
var result;
var lang = opts.language.toLowerCase();
if (lang === 'javascript') {
result = jsxgettext.generate(sources, opts);
} else if (lang in parsers) {
result = jsxgettext.generate.apply(jsxgettext, parsers[lang](sources, opts));
} else {
throw new Error("Unsupported language: " + opts.language);
}
if (opts.output === '-') {
console.log(result);
} else {
fs.writeFileSync(path.resolve(path.join(opts['output-dir'] || '', opts.output)), result, "utf8");
}
}
function main() {
var files = opts.input;

@@ -73,22 +95,2 @@ var sources = {};

function gen (sources) {
var result;
if (opts.language.toUpperCase() === 'EJS') {
result = jsxgettext.generateFromEJS(sources, opts);
} else if (opts.language.toUpperCase() === 'JINJA') {
result = jsxgettext.generateFromJinja(sources, opts);
} else if (opts.language.toUpperCase() === 'JADE') {
result = jsxgettext.generateFromJade(sources, opts);
} else if (opts.language.toUpperCase() === 'HANDLEBARS') {
result = jsxgettext.generateFromHandlebars(sources, opts);
} else {
result = jsxgettext.generate(sources, opts);
}
if (opts.output === '-') {
console.log(result);
} else {
fs.writeFileSync(path.resolve(path.join(opts['output-dir'] || '', opts.output)), result, "utf8");
}
}
main();

@@ -1,3 +0,1 @@

/* jshint node: true, undef: true */
/* global module, require */
"use strict";

@@ -14,3 +12,2 @@

var estraverse = require('estraverse');
var jade = require('jade');
var gettextParser = require('gettext-parser');

@@ -34,15 +31,27 @@

function checkExpr(node, keyword) {
var firstArg = node.arguments && node.arguments[0];
return (node.type === "CallExpression" && // must be a call expression
(
node.callee.name && // Should not be an anonymous function call
(node.callee.name === 'gettext' || // with a gettext call expr
(node.callee.name === keyword)) || // or keyword call expr
(node.callee.type === 'MemberExpression' && // or a member expr
(node.callee.property.name === 'gettext' ||
node.callee.property.name === keyword))
) &&
firstArg && (isStrConcatExpr(firstArg) || isStringLiteral(firstArg))
);
function getTranslatable(node, keyword) {
// must be a call expression with arguments
if (node.type !== "CallExpression" || !node.arguments)
return false;
var callee = node.callee;
var funcName = callee.name;
var arg = node.arguments[0];
if (!funcName) {
if (callee.type !== 'MemberExpression')
return false;
// Special case for gettext.call calls (or keyword.call)
if (callee.property.name === 'call') {
funcName = callee.object.name;
arg = node.arguments[1]; // skip context object
} else {
funcName = callee.property.name;
}
}
if ((funcName === 'gettext' || funcName === keyword) &&
arg && (isStrConcatExpr(arg) || isStringLiteral(arg)))
return arg;
}

@@ -58,4 +67,12 @@

function loadStrings(poFile) {
try {
return gettextParser.po.parse(fs.readFileSync(path.resolve(poFile)), "utf-8");
} catch (e) {
return null;
}
}
// generate extracted strings file
function gen (sources, options) {
function gen(sources, options) {
var poJSON;

@@ -89,4 +106,4 @@ if (options['join-existing'])

var ast = parser.parse(source, {
onComment: function (block, text, start, end, line, column) {
text = text.replace(/^\s*L10n:/, '')
onComment: function (block, text, start, end, line/*, column*/) {
text = text.replace(/^\s*L10n:/, '');

@@ -105,6 +122,6 @@ if (!text)

// finds comments that end on the previous line
function findComments (comments, line) {
function findComments(comments, line) {
return comments.map(function (node) {
var commentLine = node.line;
if (commentLine == line || commentLine + 1 == line) {
if (commentLine === line || commentLine + 1 === line) {
return node.value;

@@ -118,6 +135,7 @@ }

enter: function (node) {
if (!checkExpr(node, options.keyword))
var arg = getTranslatable(node, options.keyword);
if (!arg)
return;
var str = extractStr(node.arguments[0]);
var str = extractStr(arg);
var line = node.loc.start.line;

@@ -165,242 +183,2 @@ var comments = findComments(astComments, line);

// generate extracted strings file from EJS
function genEJS (ejsSources, options) {
Object.keys(ejsSources).forEach(function (filename) {
ejsSources[filename] = parseEJS(ejsSources[filename]);
});
return gen(ejsSources, options);
}
// generate extracted strings file from Jade templates
function genJade (jadeSources, options) {
Object.keys(jadeSources).forEach(function (filename) {
jadeSources[filename] = parseJade(jadeSources[filename], options);
});
return gen(jadeSources, options);
}
// generate extracted strings file from Handlebars/Mustache templates
function genHandlebars (hbSources, options) {
Object.keys(hbSources).forEach(function (filename) {
hbSources[filename] = parseHandlebars(hbSources[filename]);
});
return gen(hbSources, options);
}
// generate extracted strings file from Jinja2 templates
function genJinja (jinjaSources, options) {
Object.keys(jinjaSources).forEach(function (filename) {
jinjaSources[filename] = parseEJS(jinjaSources[filename], {open: "{{", close: "}}"});
});
return gen(jinjaSources, options);
}
function loadStrings (poFile) {
try {
return gettextParser.po.parse(fs.readFileSync(path.resolve(poFile)), "utf-8");
} catch (e) {
return null;
}
}
// strips everything but the javascript bits
function parseEJS (str, options){
options = options || {};
var open = options.open || '<%',
close = options.close || '%>';
var buf = [];
var lineno = 1;
for (var i = 0, len = str.length; i < len; ++i) {
if (str.slice(i, open.length + i) == open) {
i += open.length;
switch (str.substr(i, 1)) {
case '=':
case '-':
++i;
break;
}
var end = str.indexOf(close, i), js = str.substring(i, end), start = i, n = 0;
if ('-' == js[js.length-1]){
js = js.substring(0, js.length - 2);
}
/* jshint -W030 */
while (~(n = js.indexOf("\n", n))) n++,buf.push("\n");
/* jshint +W030 */
// skip EJS include statements which are not valid javascript
if (/^\s*include\s*[^\s]+\s*$/.test(js)) js = "";
buf.push(js, ';');
i += end - start + close.length - 1;
} else if (str.substr(i, 1) == "\n") {
buf.push("\n");
}
}
return buf.join('');
}
// From MDN:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Using_Special_Characters
function escapeRegExp(string){
return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
function parseJade(str, options) {
options = options || {};
var lineno = 1;
var parser = new jade.Parser(str);
var lexer = parser.lexer;
var token;
var gettextRegexPrefix = '(?:gettext';
if (options.keyword) {
gettextRegexPrefix += '|' + escapeRegExp(options.keyword);
}
gettextRegexPrefix += ')';
var gettexRegex = new RegExp(gettextRegexPrefix + '(?:\\(\"[^"]+\"|\\(\'[^\']+\')', 'gi');
function extractGettext(str) {
if (typeof(str) !== 'string') return '';
var tmp = str.match(gettexRegex) || [];
return tmp.map(function(t) {
return t + ')';
}).join(';');
}
function extractFromObj(key) {
/* jshint -W040 */
return extractGettext(this[key]);
}
function isEmpty(obj) {
return obj.length;
}
var buf = [], lineN, tmp;
do {
token = lexer.next();
lineN = token.line - 1;
switch(token.type) {
case 'attrs':
tmp = Object.keys(token.attrs).map(extractFromObj, token.attrs).filter(isEmpty);
if(tmp.length) buf[lineN] = tmp.join('') + ';';
break;
case 'text':
case 'code':
tmp = extractGettext(token.val);
if (tmp.length) buf[lineN] = tmp + ';';
break;
}
} while(token.type != 'eos');
return buf.join('\n');
}
// Turn handlebars helper calls into javascript-syntax functions.
// Also comment blocks are turned into javascript comments.
function parseHandlebars(str, options) {
// Using regexes for parsing, ooooh yeeeahhh!
// Short comments: {{! this is a comment }}
var shortCommentRE = /\{\{\!(.*?)\}\}/
// Long comments: {{!-- this comment has {{markup}} in it --}}
var longCommentRE = /\{\{\!--(.*?)--\}\}/
// Block helpers: {{#helper}}template content{{/helper}}
var blockHelperStartRE = /\{\{#(\w+)\}\}/
var blockHelperEndRE = /\{\{\/(\w+)\}\}/
// Function helpers: {{ helper value }} or {{ helper "some string" }}
var singleQuotedStringWithEscapes = "'(([^']*?(\\\\')?)+)'";
var doubleQuotedStringWithEscapes = '"(([^"]*?(\\\\")?)+)"';
var funcHelperRE = new RegExp("\\{\\{\\s*(\\w+)\\s+((\\w+)|(" +
singleQuotedStringWithEscapes + ")|(" +
doubleQuotedStringWithEscapes + "))\\s*\\}\\}")
var buf = [];
var match = null;
while (str.length) {
// Find the earliest match of any type of tag in the string.
match = str.match(shortCommentRE);
if (match) {
match.type = 'comment';
}
var nextMatch = str.match(longCommentRE);
if (nextMatch) {
if (!match || nextMatch.index < match.index) {
match = nextMatch;
match.type = 'comment';
}
}
nextMatch = str.match(blockHelperStartRE);
if (nextMatch) {
if (!match || nextMatch.index < match.index) {
match = nextMatch;
match.type = 'block';
}
}
nextMatch = str.match(funcHelperRE);
if (nextMatch) {
if (!match || nextMatch.index < match.index) {
match = nextMatch;
match.type = 'func';
}
}
if (!match) {
break;
}
str = str.substring(match.index + match[0].length);
// Translate the match into an appropriate chunk of javascript.
if (match.type == 'comment') {
// Template comment => javascript comment
match[1].split("\n").forEach(function(comment) {
buf.push("//");
buf.push(comment);
buf.push("\n");
})
} else if (match.type == 'block') {
// Template block helper => javascript function call
var helperName = match[1];
buf.push(helperName)
buf.push('("')
var endMatch = str.match(blockHelperEndRE);
while (endMatch && endMatch[1] !== helperName) {
var skipTo = endMatch.index + endMatch[0].length;
buf.push(str.substring(0, skipTo).replace('"', '\\"'));
str = str.substring(skipTo);
endMatch = str.match(blockHelperEndRE);
}
if (endMatch) {
buf.push(str.substring(0, endMatch.index).replace('"', '\\"'));
str = str.substring(endMatch.index + endMatch[0].length);
} else {
buf.push(str.replace('"', '\\"'));
str = '';
}
buf.push('")\n');
} else if (match.type == 'func') {
// Template function helper => javascript function call
buf.push(match[1]);
buf.push('(');
buf.push(match[2]);
buf.push(')\n');
}
}
return buf.join('');
}
exports.generate = gen;
exports.generateFromEJS = genEJS;
exports.generateFromJade = genJade;
exports.generateFromHandlebars = genHandlebars;
exports.generateFromJinja = genJinja;
exports.generate = gen;
{
"author": "Zach Carter",
"author": "Zach Carter <zcarter@mozilla.com> (http://twitter.com/zii)",
"contributors": [
"Burak Yigit Kaya <me@byk.im> (http://byk.im)",
"Kaare A. Larsen <kaare.a.larsen@gmail.com> (http://bottleno.se)",
"Austin King <shout@ozten.com> (https://ozten.com)",
"Lloyd Hilaiel <lloyd@hilaiel.com> (http://lloyd.io)",
"Francois Marier <francois@fmarier.org> (http://fmarier.org)",
"Andris Reinman <andris.reinman@gmail.com> (http://www.andrisreinman.com)",
"Vlad Filippov <github@vf.io> (http://vf.io)",
"Michael Weibel (https://github.com/mweibel)",
"Eduardo Vaz de Mello (https://github.com/wirapuru)",
"Ryan Kelly <ryan@rfk.id.au> (http://www.rfk.id.au)"
],
"name": "jsxgettext",
"description": "Extract gettext calls from JavaScript and EJS files",
"version": "0.3.4",
"version": "0.3.5",
"license": "MPL-2.0",
"description": "Extracts gettext strings from JavaScript, EJS, Jade, Jinja and Handlebars files.",
"keywords": ["i18n", "internationalization", "gettext", "xgettext"],
"homepage": "https://github.com/zaach/jsxgettext",
"bugs": "https://github.com/zaach/jsxgettext/issues",
"repository": {

@@ -21,11 +37,8 @@ "type": "git",

"devDependencies": {
"jshint": "~2.4.1",
"test": "*"
},
"optionalDependencies": {},
"engines": {
"node": "*"
},
"scripts": {
"test": "node tests/all.js"
"test": "node ./node_modules/jshint . && node test"
}
}
# jsxgettext [![Build Status](https://travis-ci.org/zaach/jsxgettext.png)](https://travis-ci.org/zaach/jsxgettext) [![NPM version](https://badge.fury.io/js/jsxgettext.png)](http://badge.fury.io/js/jsxgettext)
A node module with a CLI that extracts gettext strings from JavaScript and EJS files. It also extracts comments that begin with "L10n:" when they appear above a `gettext` call.
A node module with a CLI that extracts gettext strings from JavaScript, EJS, Jade, Jinja and Handlebars files. Uses a real parser, [acorn](https://github.com/marijnh/acorn), for JavaScript files and recognizes the following uses:
```javascript
gettext("Hello world!");
gettext("Hello" + ' world!');
myModule.gettext("Hello " + 'world!');
gettext.call(myObj, "Hello " + 'world!');
```
It also extracts comments that begin with "L10n:" when they appear above a `gettext` call:
```javascript
// L10n: Salutation to the world
gettext("Hello world!");
```
## Install

@@ -31,4 +45,2 @@

-j, --join-existing join messages with existing file
-L NAME, --language NAME recognise the specified language (JavaScript, EJS, Jinja)
-L NAME, --language NAME use the specified language (javascript, ejs, jinja, handlebars, jade)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc