Socket
Socket
Sign inDemoInstall

i18next-scanner

Package Overview
Dependencies
Maintainers
1
Versions
92
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

i18next-scanner - npm Package Compare versions

Comparing version 1.2.1 to 1.3.0

58

lib/parser.js

@@ -168,2 +168,5 @@ 'use strict';

var Parser = function () {
// The resStore stores all translation keys including unused ones
function Parser(options) {

@@ -176,2 +179,3 @@ var _this = this;

this.resStore = {};
this.resScan = {};

@@ -185,2 +189,3 @@ this.options = transformOptions(_lodash2.default.extend({}, this.options, options));

_this.resStore[lng] = _this.resStore[lng] || {};
_this.resScan[lng] = _this.resScan[lng] || {};
namespaces.forEach(function (ns) {

@@ -190,2 +195,3 @@ var resPath = _this.formatResourceLoadPath(lng, ns);

_this.resStore[lng][ns] = {};
_this.resScan[lng][ns] = {};
try {

@@ -206,2 +212,5 @@ var stat = _fs2.default.statSync(resPath);

// The resScan only stores translation keys parsed from code
_createClass(Parser, [{

@@ -391,3 +400,8 @@ key: 'debuglog',

var resStore = _lodash2.default.assign({}, this.resStore);
var resStore = {};
if (this.options.removeUnusedKeys) {
resStore = this.resScan;
} else {
resStore = this.resStore;
}

@@ -495,8 +509,8 @@ if (opts.sort) {

this.options.lngs.forEach(function (lng) {
var res = _this4.resStore[lng] && _this4.resStore[lng][ns];
var resLoad = _this4.resStore[lng] && _this4.resStore[lng][ns];
var resScan = _this4.resScan[lng] && _this4.resScan[lng][ns];
if (!_lodash2.default.isObject(res)) {
if (!_lodash2.default.isObject(resLoad)) {
// skip undefined namespace
console.log('The namespace "' + ns + '" does not exist:', { key: key, options: options });
return;

@@ -509,4 +523,6 @@ }

if (index < keys.length - 1) {
res[key] = res[key] || {};
res = res[key];
resLoad[key] = resLoad[key] || {};
resLoad = resLoad[key];
resScan[key] = resScan[key] || {};
resScan = resScan[key];

@@ -551,20 +567,26 @@ return; // continue

// Use `options.defaultValue` if specified
if (res[key] === undefined) {
res[key] = options.defaultValue;
_this4.debuglog('Added a new translation key { %s: %s } to %s', JSON.stringify(key), JSON.stringify(res[key]), JSON.stringify(_this4.formatResourceLoadPath(lng, ns)));
if (resLoad[key] === undefined) {
resLoad[key] = options.defaultValue;
_this4.debuglog('Added a new translation key { %s: %s } to %s', JSON.stringify(key), JSON.stringify(resLoad[key]), JSON.stringify(_this4.formatResourceLoadPath(lng, ns)));
}
if (formattedKey !== key && res[formattedKey] === undefined) {
res[formattedKey] = options.defaultValue;
_this4.debuglog('Added a new translation key { %s: %s } to %s', JSON.stringify(formattedKey), JSON.stringify(res[formattedKey]), JSON.stringify(_this4.formatResourceLoadPath(lng, ns)));
resScan[key] = resLoad[key];
if (formattedKey !== key && resLoad[formattedKey] === undefined) {
resLoad[formattedKey] = options.defaultValue;
_this4.debuglog('Added a new translation key { %s: %s } to %s', JSON.stringify(formattedKey), JSON.stringify(resLoad[formattedKey]), JSON.stringify(_this4.formatResourceLoadPath(lng, ns)));
}
resScan[formattedKey] = resLoad[formattedKey];
} else {
// Fallback to `this.options.defaultValue`
if (res[key] === undefined) {
res[key] = _lodash2.default.isFunction(_this4.options.defaultValue) ? _this4.options.defaultValue(lng, ns, key, options) : _this4.options.defaultValue;
_this4.debuglog('Added a new translation key { %s: %s } to %s', JSON.stringify(key), JSON.stringify(res[key]), JSON.stringify(_this4.formatResourceLoadPath(lng, ns)));
if (resLoad[key] === undefined) {
resLoad[key] = _lodash2.default.isFunction(_this4.options.defaultValue) ? _this4.options.defaultValue(lng, ns, key, options) : _this4.options.defaultValue;
_this4.debuglog('Added a new translation key { %s: %s } to %s', JSON.stringify(key), JSON.stringify(resLoad[key]), JSON.stringify(_this4.formatResourceLoadPath(lng, ns)));
}
if (formattedKey !== key && res[formattedKey] === undefined) {
res[formattedKey] = _lodash2.default.isFunction(_this4.options.defaultValue) ? _this4.options.defaultValue(lng, ns, key, options) : _this4.options.defaultValue;
_this4.debuglog('Added a new translation key { %s: %s } to %s', JSON.stringify(formattedKey), JSON.stringify(res[formattedKey]), JSON.stringify(_this4.formatResourceLoadPath(lng, ns)));
resScan[key] = resLoad[key];
if (formattedKey !== key && resLoad[formattedKey] === undefined) {
resLoad[formattedKey] = _lodash2.default.isFunction(_this4.options.defaultValue) ? _this4.options.defaultValue(lng, ns, key, options) : _this4.options.defaultValue;
_this4.debuglog('Added a new translation key { %s: %s } to %s', JSON.stringify(formattedKey), JSON.stringify(resLoad[formattedKey]), JSON.stringify(_this4.formatResourceLoadPath(lng, ns)));
}
resScan[formattedKey] = resLoad[formattedKey];
}

@@ -571,0 +593,0 @@ });

{
"name": "i18next-scanner",
"version": "1.2.1",
"version": "1.3.0",
"description": "Scan your code, extract translation keys/values, and merge them into i18n resource files.",

@@ -41,16 +41,16 @@ "homepage": "https://github.com/i18next/i18next-scanner",

"esprima": "^2.7.2",
"lodash": "^4.6.1",
"through2": "^2.0.0",
"vinyl": "^1.1.0",
"vinyl-fs": "^2.2.1"
"lodash": "^4.12.0",
"through2": "^2.0.1",
"vinyl": "^1.1.1",
"vinyl-fs": "^2.4.3"
},
"devDependencies": {
"babel-cli": "^6.6.5",
"babel-core": "^6.7.2",
"babel-eslint": "^6.0.0-beta.6",
"babel-cli": "^6.8.0",
"babel-core": "^6.8.0",
"babel-eslint": "^6.0.4",
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.6.0",
"babel-preset-stage-0": "^6.5.0",
"coveralls": "^2.11.8",
"eslint": "^2.4.0",
"coveralls": "^2.11.9",
"eslint": "^2.10.1",
"gulp": "^3.9.1",

@@ -60,5 +60,5 @@ "gulp-tap": "^0.1.3",

"sha1": "^1.1.1",
"tap": "^5.7.0",
"tap": "^5.7.1",
"text-table": "^0.2.0"
}
}

@@ -307,2 +307,3 @@ # i18next-scanner [![build status](https://travis-ci.org/i18next/i18next-scanner.svg?branch=master)](https://travis-ci.org/i18next/i18next-scanner) [![Coverage Status](https://coveralls.io/repos/i18next/i18next-scanner/badge.svg?branch=master&service=github)](https://coveralls.io/github/i18next/i18next-scanner?branch=master)

debug: false,
removeUnusedKeys: false,
sort: false,

@@ -342,2 +343,8 @@ attr: {

#### removeUnusedKeys
Type: `Boolean` Default: `false`
Set to `true` to remove unused translation keys from i18n resource files.
#### sort

@@ -344,0 +351,0 @@

@@ -149,4 +149,9 @@ /* eslint no-console: 0 */

options = _.assign({}, defaults);
// The resStore stores all translation keys including unused ones
resStore = {};
// The resScan only stores translation keys parsed from code
resScan = {};
constructor(options) {

@@ -160,2 +165,3 @@ this.options = transformOptions(_.extend({}, this.options, options));

this.resStore[lng] = this.resStore[lng] || {};
this.resScan[lng] = this.resScan[lng] || {};
namespaces.forEach((ns) => {

@@ -165,2 +171,3 @@ const resPath = this.formatResourceLoadPath(lng, ns);

this.resStore[lng][ns] = {};
this.resScan[lng][ns] = {};
try {

@@ -336,3 +343,8 @@ const stat = fs.statSync(resPath);

const resStore = _.assign({}, this.resStore);
let resStore = {};
if (this.options.removeUnusedKeys) {
resStore = this.resScan;
} else {
resStore = this.resStore;
}

@@ -435,7 +447,7 @@ if (opts.sort) { // sort by key

this.options.lngs.forEach((lng) => {
let res = this.resStore[lng] && this.resStore[lng][ns];
let resLoad = this.resStore[lng] && this.resStore[lng][ns];
let resScan = this.resScan[lng] && this.resScan[lng][ns];
if (!_.isObject(res)) { // skip undefined namespace
if (!_.isObject(resLoad)) { // skip undefined namespace
console.log('The namespace "' + ns + '" does not exist:', { key, options });
return;

@@ -448,4 +460,6 @@ }

if (index < (keys.length - 1)) {
res[key] = res[key] || {};
res = res[key];
resLoad[key] = resLoad[key] || {};
resLoad = resLoad[key];
resScan[key] = resScan[key] || {};
resScan = resScan[key];

@@ -489,22 +503,25 @@ return; // continue

// Use `options.defaultValue` if specified
if (res[key] === undefined) {
res[key] = options.defaultValue;
if (resLoad[key] === undefined) {
resLoad[key] = options.defaultValue;
this.debuglog('Added a new translation key { %s: %s } to %s',
JSON.stringify(key),
JSON.stringify(res[key]),
JSON.stringify(resLoad[key]),
JSON.stringify(this.formatResourceLoadPath(lng, ns))
);
}
if ((formattedKey !== key) && (res[formattedKey] === undefined)) {
res[formattedKey] = options.defaultValue;
resScan[key] = resLoad[key];
if ((formattedKey !== key) && (resLoad[formattedKey] === undefined)) {
resLoad[formattedKey] = options.defaultValue;
this.debuglog('Added a new translation key { %s: %s } to %s',
JSON.stringify(formattedKey),
JSON.stringify(res[formattedKey]),
JSON.stringify(resLoad[formattedKey]),
JSON.stringify(this.formatResourceLoadPath(lng, ns))
);
}
resScan[formattedKey] = resLoad[formattedKey];
} else {
// Fallback to `this.options.defaultValue`
if (res[key] === undefined) {
res[key] = _.isFunction(this.options.defaultValue)
if (resLoad[key] === undefined) {
resLoad[key] = _.isFunction(this.options.defaultValue)
? this.options.defaultValue(lng, ns, key, options)

@@ -514,8 +531,10 @@ : this.options.defaultValue;

JSON.stringify(key),
JSON.stringify(res[key]),
JSON.stringify(resLoad[key]),
JSON.stringify(this.formatResourceLoadPath(lng, ns))
);
}
if ((formattedKey !== key) && (res[formattedKey] === undefined)) {
res[formattedKey] = _.isFunction(this.options.defaultValue)
resScan[key] = resLoad[key];
if ((formattedKey !== key) && (resLoad[formattedKey] === undefined)) {
resLoad[formattedKey] = _.isFunction(this.options.defaultValue)
? this.options.defaultValue(lng, ns, key, options)

@@ -525,6 +544,7 @@ : this.options.defaultValue;

JSON.stringify(formattedKey),
JSON.stringify(res[formattedKey]),
JSON.stringify(resLoad[formattedKey]),
JSON.stringify(this.formatResourceLoadPath(lng, ns))
);
}
resScan[formattedKey] = resLoad[formattedKey];
}

@@ -531,0 +551,0 @@ });

{
"language": {
"en-US": "English"
"de-DE": "German"
}
}

@@ -5,3 +5,4 @@ {

"8524de963f07201e5c086830d370797f": "Loading...",
"b04ba49f848624bb97ab094a2631d2ad74913498": "Loading..."
"b04ba49f848624bb97ab094a2631d2ad74913498": "Loading...",
"Loading...": "Loading..."
}

@@ -244,1 +244,139 @@ import _ from 'lodash';

});
test('Keep old translations', function(t) {
const options = _.merge({}, defaults, {
resource: {
loadPath: 'test/fixtures/i18n/{{lng}}/{{ns}}.json',
savePath: 'i18n/{{lng}}/{{ns}}.json'
}
});
gulp.src('test/fixtures/modules/**/*.js')
.pipe(scanner(options))
.pipe(tap(function(file) {
const contents = file.contents.toString();
// English - locale.json
if (file.path === 'i18n/en/locale.json') {
const found = JSON.parse(contents);
const wanted = {
"language": {
"en-US": "English"
}
};
t.same(found, wanted);
}
// English - resource.json
if (file.path === 'i18n/en/resource.json') {
const found = JSON.parse(contents);
const wanted = {
"loading": "Loading...",
"cd643ef3": "Loading...",
"8524de963f07201e5c086830d370797f": "Loading...",
"b04ba49f848624bb97ab094a2631d2ad74913498": "Loading...",
"Loading...": "Loading...", // Note. This is an existing translation key in English resource file.
"This value does not exist.": "__STRING_NOT_TRANSLATED__",
"YouTube has more than {{count}} billion users.": "__STRING_NOT_TRANSLATED__",
"YouTube has more than {{count}} billion users._plural": "__STRING_NOT_TRANSLATED__",
"You have {{count}} messages.": "__STRING_NOT_TRANSLATED__",
"You have {{count}} messages._plural": "__STRING_NOT_TRANSLATED__"
};
t.same(found, wanted);
}
// German - locale.json
if (file.path === 'i18n/de/locale.json') {
const found = JSON.parse(contents);
const wanted = {
"language": {
"de-DE": "German"
}
};
t.same(found, wanted);
}
// German - resource.json
if (file.path === 'i18n/de/resource.json') {
const found = JSON.parse(contents);
const wanted = {
"loading": "Wird geladen...",
"cd643ef3": "Wird geladen...",
"8524de963f07201e5c086830d370797f": "Wird geladen...",
"b04ba49f848624bb97ab094a2631d2ad74913498": "Wird geladen...",
"Loading...": "__STRING_NOT_TRANSLATED__",
"This value does not exist.": "__STRING_NOT_TRANSLATED__",
"YouTube has more than {{count}} billion users.": "__STRING_NOT_TRANSLATED__",
"YouTube has more than {{count}} billion users._plural": "__STRING_NOT_TRANSLATED__",
"You have {{count}} messages.": "__STRING_NOT_TRANSLATED__",
"You have {{count}} messages._plural": "__STRING_NOT_TRANSLATED__"
};
t.same(found, wanted);
}
}))
.on('end', function() {
t.end();
});
});
// https://github.com/i18next/i18next-scanner/issues/30
test('Remove old translation keys which are already removed from code', function(t) {
const options = _.merge({}, defaults, {
removeUnusedKeys: true,
resource: {
loadPath: 'test/fixtures/i18n/{{lng}}/{{ns}}.json',
savePath: 'i18n/{{lng}}/{{ns}}.json'
}
});
gulp.src('test/fixtures/modules/**/*.js')
.pipe(scanner(options))
.pipe(tap(function(file) {
const contents = file.contents.toString();
// English - locale.json
if (file.path === 'i18n/en/locale.json') {
const found = JSON.parse(contents);
const wanted = {};
t.same(found, wanted);
}
// English - resource.json
if (file.path === 'i18n/en/resource.json') {
const found = JSON.parse(contents);
const wanted = {
"Loading...": "Loading...", // Note. This is an existing translation key in English resource file.
"This value does not exist.": "__STRING_NOT_TRANSLATED__",
"YouTube has more than {{count}} billion users.": "__STRING_NOT_TRANSLATED__",
"YouTube has more than {{count}} billion users._plural": "__STRING_NOT_TRANSLATED__",
"You have {{count}} messages.": "__STRING_NOT_TRANSLATED__",
"You have {{count}} messages._plural": "__STRING_NOT_TRANSLATED__"
};
t.same(found, wanted);
}
// German - locale.json
if (file.path === 'i18n/de/locale.json') {
const found = JSON.parse(contents);
const wanted = {};
t.same(found, wanted);
}
// German - resource.json
if (file.path === 'i18n/de/resource.json') {
const found = JSON.parse(contents);
const wanted = {
"Loading...": "__STRING_NOT_TRANSLATED__",
"This value does not exist.": "__STRING_NOT_TRANSLATED__",
"YouTube has more than {{count}} billion users.": "__STRING_NOT_TRANSLATED__",
"YouTube has more than {{count}} billion users._plural": "__STRING_NOT_TRANSLATED__",
"You have {{count}} messages.": "__STRING_NOT_TRANSLATED__",
"You have {{count}} messages._plural": "__STRING_NOT_TRANSLATED__"
};
t.same(found, wanted);
}
}))
.on('end', function() {
t.end();
});
});
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