i18next-scanner
Advanced tools
Comparing version 1.9.4 to 2.0.0
@@ -48,2 +48,4 @@ 'use strict'; | ||
parser.parseFuncFromString(content); | ||
// Look for Trans components in JSX | ||
parser.parseTransFromString(content); | ||
} | ||
@@ -50,0 +52,0 @@ |
@@ -74,2 +74,6 @@ 'use strict'; | ||
var _parse = require('parse5'); | ||
var _parse2 = _interopRequireDefault(_parse); | ||
var _ensureArray = require('./ensure-array'); | ||
@@ -79,2 +83,6 @@ | ||
var _jsxParser = require('./jsx-parser'); | ||
var _jsxParser2 = _interopRequireDefault(_jsxParser); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -431,2 +439,31 @@ | ||
} | ||
// Parses translation keys from `Trans` components in JSX | ||
// <Trans i18nKey="some.key">Default text</Trans> | ||
}, { | ||
key: 'parseTransFromString', | ||
value: function parseTransFromString(content) { | ||
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var customHandler = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
var pattern = '<Trans[^]*?i18nKey="([^"]+)"[^]*?>([^]*?)</\\s*Trans\\s*>'; | ||
var re = new RegExp(pattern, 'gim'); | ||
var setter = this.set.bind(this); | ||
if ((0, _isFunction2.default)(opts)) { | ||
setter = opts; | ||
opts = {}; | ||
} | ||
var r = void 0; | ||
while (r = re.exec(content)) { | ||
var _key3 = (0, _trim2.default)(r[1]); | ||
var fragment = (0, _trim2.default)(r[2]); | ||
fragment = fragment.replace(/\s+/g, ' '); | ||
var defaultValue = (0, _jsxParser2.default)(fragment); | ||
var _options = { defaultValue: defaultValue }; | ||
setter(_key3, _options); | ||
} | ||
return this; | ||
} | ||
// Parses translation keys from `data-i18n` attribute in HTML | ||
@@ -439,9 +476,9 @@ // <div data-i18n="[attr]ns:foo.bar;[attr]ns:foo.baz"> | ||
value: function parseAttrFromString(content) { | ||
var _this3 = this; | ||
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var customHandler = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
var setter = this.set.bind(this); | ||
if ((0, _isFunction2.default)(opts)) { | ||
customHandler = opts; | ||
setter = opts; | ||
opts = {}; | ||
@@ -456,36 +493,38 @@ } | ||
var matchPattern = attrs.map(function (attr) { | ||
return '(?:' + attr + ')'; | ||
}).join('|').replace(/\./g, '\\.'); | ||
var pattern = '(?:(?:^[\\s]*)|[^a-zA-Z0-9_])(?:' + matchPattern + ')=("[^"]*"|\'[^\']*\')'; | ||
var re = new RegExp(pattern, 'gim'); | ||
var ast = _parse2.default.parse(content); | ||
var r = void 0; | ||
var parseAttributeValue = function parseAttributeValue(key) { | ||
key = (0, _trim2.default)(key); | ||
if (key.length === 0) { | ||
return; | ||
} | ||
if (key.indexOf('[') === 0) { | ||
var parts = key.split(']'); | ||
key = parts[1]; | ||
} | ||
if (key.indexOf(';') === key.length - 1) { | ||
key = key.substr(0, key.length - 2); | ||
} | ||
while (r = re.exec(content)) { | ||
var attr = (0, _trim2.default)(r[1], '\'"'); | ||
var keys = attr.indexOf(';') >= 0 ? attr.split(';') : [attr]; | ||
setter(key); | ||
}; | ||
keys.forEach(function (key) { | ||
key = (0, _trim2.default)(key); | ||
if (key.length === 0) { | ||
return; | ||
var walk = function walk(nodes) { | ||
nodes.forEach(function (node) { | ||
if (node.attrs) { | ||
node.attrs.forEach(function (attr) { | ||
if (attrs.indexOf(attr.name) !== -1) { | ||
var values = attr.value.split(';'); | ||
values.forEach(parseAttributeValue); | ||
} | ||
}); | ||
} | ||
if (key.indexOf('[') === 0) { | ||
var parts = key.split(']'); | ||
key = parts[1]; | ||
if (node.childNodes) { | ||
walk(node.childNodes); | ||
} | ||
if (key.indexOf(';') === key.length - 1) { | ||
key = key.substr(0, key.length - 2); | ||
} | ||
}); | ||
}; | ||
if (customHandler) { | ||
customHandler(key); | ||
return; | ||
} | ||
walk(ast.childNodes); | ||
_this3.set(key); | ||
}); | ||
} | ||
return this; | ||
@@ -584,3 +623,3 @@ } | ||
value: function set(key) { | ||
var _this4 = this; | ||
var _this3 = this; | ||
@@ -619,11 +658,11 @@ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var _options = this.options, | ||
lngs = _options.lngs, | ||
context = _options.context, | ||
contextFallback = _options.contextFallback, | ||
contextSeparator = _options.contextSeparator, | ||
plural = _options.plural, | ||
pluralFallback = _options.pluralFallback, | ||
pluralSeparator = _options.pluralSeparator, | ||
defaultValue = _options.defaultValue; | ||
var _options2 = this.options, | ||
lngs = _options2.lngs, | ||
context = _options2.context, | ||
contextFallback = _options2.contextFallback, | ||
contextSeparator = _options2.contextSeparator, | ||
plural = _options2.plural, | ||
pluralFallback = _options2.pluralFallback, | ||
pluralSeparator = _options2.pluralSeparator, | ||
defaultValue = _options2.defaultValue; | ||
@@ -633,8 +672,8 @@ var keys = (0, _isString2.default)(keySeparator) ? key.split(keySeparator) : [key]; | ||
lngs.forEach(function (lng) { | ||
var resLoad = _this4.resStore[lng] && _this4.resStore[lng][ns]; | ||
var resScan = _this4.resScan[lng] && _this4.resScan[lng][ns]; | ||
var resLoad = _this3.resStore[lng] && _this3.resStore[lng][ns]; | ||
var resScan = _this3.resScan[lng] && _this3.resScan[lng][ns]; | ||
if (!(0, _isObject2.default)(resLoad)) { | ||
// Skip undefined namespace | ||
_this4.log('The namespace "' + ns + '" does not exist:', { key: key, options: options }); | ||
_this3.log('The namespace "' + ns + '" does not exist:', { key: key, options: options }); | ||
return; | ||
@@ -724,3 +763,3 @@ } | ||
} | ||
_this4.log('Added a new translation key { %s: %s } to %s', JSON.stringify(resKey), JSON.stringify(resLoad[resKey]), JSON.stringify(_this4.formatResourceLoadPath(lng, ns))); | ||
_this3.log('Added a new translation key { %s: %s } to %s', JSON.stringify(resKey), JSON.stringify(resLoad[resKey]), JSON.stringify(_this3.formatResourceLoadPath(lng, ns))); | ||
} | ||
@@ -727,0 +766,0 @@ |
{ | ||
"name": "i18next-scanner", | ||
"version": "1.9.4", | ||
"version": "2.0.0", | ||
"description": "Scan your code, extract translation keys/values, and merge them into i18n resource files.", | ||
@@ -16,13 +16,8 @@ "homepage": "https://github.com/i18next/i18next-scanner", | ||
"scripts": { | ||
"prepublish": "npm run lint && npm run build && npm test", | ||
"prepublish": "npm run eslint && npm run build && npm test", | ||
"build": "babel ./src --out-dir ./lib", | ||
"test": "tap test/*.js --node-arg=--require --node-arg=babel-register --node-arg=--require --node-arg=babel-polyfill", | ||
"lint": "eslint ./src", | ||
"lint:fix": "eslint --fix ./src", | ||
"precommit-check": "npm run lint", | ||
"coveralls": "tap test/*.js --coverage --coverage-report=text-lcov --nyc-arg=--require --nyc-arg=babel-register --nyc-arg=--require --nyc-arg=babel-polyfill | coveralls" | ||
"eslint": "eslint ./src", | ||
"coveralls": "tap test/*.js --coverage --coverage-report=text-lcov --nyc-arg=--require --nyc-arg=babel-register --nyc-arg=--require --nyc-arg=babel-polyfill | coveralls", | ||
"test": "tap test/*.js --node-arg=--require --node-arg=babel-register --node-arg=--require --node-arg=babel-polyfill" | ||
}, | ||
"pre-commit": [ | ||
"precommit-check" | ||
], | ||
"repository": { | ||
@@ -34,3 +29,3 @@ "type": "git", | ||
"engines": { | ||
"node": ">=0.10.x" | ||
"node": ">=4" | ||
}, | ||
@@ -51,22 +46,22 @@ "keywords": [ | ||
"lodash": "^4.17.4", | ||
"parse5": "^3.0.2", | ||
"through2": "^2.0.3", | ||
"vinyl": "^2.0.2", | ||
"vinyl": "^2.1.0", | ||
"vinyl-fs": "^2.4.4" | ||
}, | ||
"devDependencies": { | ||
"babel-cli": "^6.24.1", | ||
"babel-core": "^6.25.0", | ||
"babel-eslint": "^7.2.3", | ||
"babel-cli": "^6.26.0", | ||
"babel-core": "^6.26.0", | ||
"babel-eslint": "^8.0.0", | ||
"babel-preset-es2015": "^6.24.1", | ||
"babel-preset-stage-0": "^6.24.1", | ||
"coveralls": "^2.13.1", | ||
"eslint": "^3.17.1", | ||
"eslint": "^4.7.0", | ||
"gulp": "^3.9.1", | ||
"gulp-tap": "^0.1.3", | ||
"gulp-tap": "^1.0.1", | ||
"gulp-util": "^3.0.8", | ||
"sha1": "^1.1.1", | ||
"tap": "^10.3.3", | ||
"text-table": "^0.2.0", | ||
"which": "~1.2.14" | ||
"tap": "^10.7.2", | ||
"text-table": "^0.2.0" | ||
} | ||
} |
@@ -7,2 +7,32 @@ # 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) | ||
Turns your code | ||
```js | ||
i18n._('Loading...'); | ||
i18n._('Backslashes in single quote: \' \\ \''); | ||
i18n._('This is \ | ||
a multiline \ | ||
string'); | ||
i18n.t('car', { context: 'blue', count: 1 }); // output: 'One blue car' | ||
i18n.t('car', { context: 'blue', count: 2 }); // output: '2 blue cars' | ||
<Trans i18nKey="some.key">Default text</Trans> | ||
``` | ||
into resource files | ||
```js | ||
{ | ||
"Loading...": "Wird geladen...", // uses existing translation | ||
"Backslashes in single quote: ' \\ '": "__NOT_TRANSLATED__", // returns a custom string | ||
"This is a multiline string": "this is a multiline string", // returns the key as the default value | ||
"car": "car", | ||
"car_blue": "One blue car", | ||
"car_blue_plural": "{{count}} blue cars", | ||
"some": { | ||
"key": "Default text" | ||
} | ||
} | ||
``` | ||
## Notice | ||
@@ -15,2 +45,3 @@ There is a major breaking change since v1.0, and the API interface and options are not compatible with v0.x. | ||
* Fully compatible with [i18next](https://github.com/i18next/i18next) - a full-featured i18n javascript library for translating your webapplication. | ||
* Support [react-i18next](https://github.com/i18next/react-i18next) for parsing the <b>Trans</b> component | ||
* Support [Key Based Fallback](http://i18next.com/translate/keyBasedFallback/) to write your code without the need to maintain i18n keys. This feature is available since [i18next@^2.1.0](https://github.com/i18next/i18next/blob/master/CHANGELOG.md#210) | ||
@@ -30,11 +61,11 @@ * A standalone parser API | ||
```js | ||
var fs = require('fs'); | ||
var Parser = require('i18next-scanner').Parser; | ||
const fs = require('fs'); | ||
const Parser = require('i18next-scanner').Parser; | ||
var customHandler = function(key) { | ||
const customHandler = function(key) { | ||
parser.set(key, '__TRANSLATION__'); | ||
}; | ||
var parser = new Parser(); | ||
var content = ''; | ||
const parser = new Parser(); | ||
const content = ''; | ||
@@ -48,4 +79,10 @@ // Parse Translation Function | ||
.parseFuncFromString(content, { list: ['i18next.t']}, customHandler) | ||
.parseFuncFromString(content); // using default options and handler | ||
.parseFuncFromString(content); // use default options and handler | ||
// Parse Trans component | ||
content = fs.readFileSync('/path/to/app.jsx', 'utf-8'); | ||
parser | ||
.parseFuncFromString(content, customHandler) // pass a custom handler | ||
.parseFuncFromString(content); // use default options and handler | ||
// Parse HTML Attribute | ||
@@ -70,6 +107,6 @@ // <div data-i18n="key"></div> | ||
```js | ||
var scanner = require('i18next-scanner'); | ||
var vfs = require('vinyl-fs'); | ||
var sort = require('gulp-sort'); | ||
var options = { | ||
const scanner = require('i18next-scanner'); | ||
const vfs = require('vinyl-fs'); | ||
const sort = require('gulp-sort'); | ||
const options = { | ||
// See options at https://github.com/i18next/i18next-scanner#options | ||
@@ -94,5 +131,5 @@ }; | ||
```js | ||
var gulp = require('gulp'); | ||
var sort = require('gulp-sort'); | ||
var scanner = require('i18next-scanner'); | ||
const gulp = require('gulp'); | ||
const sort = require('gulp-sort'); | ||
const scanner = require('i18next-scanner'); | ||
@@ -147,9 +184,12 @@ gulp.task('i18next', function() { | ||
```js | ||
var Parser = require('i18next-scanner').Parser; | ||
var parser = new Parser(options); | ||
const Parser = require('i18next-scanner').Parser; | ||
const parser = new Parser(options); | ||
var code = "i18next.t('key'); ..."; | ||
parser.parseFuncFromString(content); | ||
const code = "i18next.t('key'); ..."; | ||
parser.parseFuncFromString(code); | ||
var html = '<div data-i18n="key"></div>'; | ||
const jsx = '<Trans i18nKey="some.key">Default text</Trans>'; | ||
parser.parseTransFromString(jsx); | ||
const html = '<div data-i18n="key"></div>'; | ||
parser.parseAttrFromString(html); | ||
@@ -177,2 +217,13 @@ | ||
#### parser.parseTransFromString | ||
Parse translation key from the [Trans component](https://github.com/i18next/react-i18next) | ||
```js | ||
parser.parseTransFromString(content); | ||
parser.parseTransFromString(content, function(key, options) { | ||
options.defaultValue = key; // use key as the value | ||
parser.set(key, options); | ||
}); | ||
``` | ||
#### parser.parseAttrFromString | ||
@@ -210,2 +261,3 @@ Parse translation key from HTML attribute | ||
``` | ||
#### parser.set | ||
@@ -566,4 +618,2 @@ Set a translation key with an optional defaultValue to i18n resource store | ||
Copyright (c) 2015-2016 Cheton Wu | ||
Licensed under the [MIT License](https://github.com/i18next/i18next-scanner/blob/master/LICENSE). | ||
MIT |
@@ -23,2 +23,4 @@ import fs from 'fs'; | ||
parser.parseFuncFromString(content); | ||
// Look for Trans components in JSX | ||
parser.parseTransFromString(content); | ||
} | ||
@@ -25,0 +27,0 @@ |
@@ -18,3 +18,5 @@ /* eslint no-console: 0 */ | ||
import { parse } from 'esprima'; | ||
import parse5 from 'parse5'; | ||
import ensureArray from './ensure-array'; | ||
import jsxToText from './jsx-parser'; | ||
@@ -342,2 +344,25 @@ const defaults = { | ||
} | ||
// Parses translation keys from `Trans` components in JSX | ||
// <Trans i18nKey="some.key">Default text</Trans> | ||
parseTransFromString(content, opts = {}, customHandler = null) { | ||
const pattern = '<Trans[^]*?i18nKey="([^"]+)"[^]*?>([^]*?)</\\s*Trans\\s*>'; | ||
const re = new RegExp(pattern, 'gim'); | ||
let setter = this.set.bind(this); | ||
if (isFunction(opts)) { | ||
setter = opts; | ||
opts = {}; | ||
} | ||
let r; | ||
while ((r = re.exec(content))) { | ||
const key = trim(r[1]); | ||
let fragment = trim(r[2]); | ||
fragment = fragment.replace(/\s+/g, ' '); | ||
const defaultValue = jsxToText(fragment); | ||
const options = { defaultValue }; | ||
setter(key, options); | ||
} | ||
return this; | ||
} | ||
// Parses translation keys from `data-i18n` attribute in HTML | ||
@@ -347,4 +372,6 @@ // <div data-i18n="[attr]ns:foo.bar;[attr]ns:foo.baz"> | ||
parseAttrFromString(content, opts = {}, customHandler = null) { | ||
let setter = this.set.bind(this); | ||
if (isFunction(opts)) { | ||
customHandler = opts; | ||
setter = opts; | ||
opts = {}; | ||
@@ -361,39 +388,38 @@ } | ||
const matchPattern = attrs | ||
.map(attr => ('(?:' + attr + ')')) | ||
.join('|') | ||
.replace(/\./g, '\\.'); | ||
const pattern = '(?:(?:^[\\s]*)|[^a-zA-Z0-9_])(?:' + matchPattern + ')=("[^"]*"|\'[^\']*\')'; | ||
const re = new RegExp(pattern, 'gim'); | ||
const ast = parse5.parse(content); | ||
let r; | ||
const parseAttributeValue = (key) => { | ||
key = trim(key); | ||
if (key.length === 0) { | ||
return; | ||
} | ||
if (key.indexOf('[') === 0) { | ||
const parts = key.split(']'); | ||
key = parts[1]; | ||
} | ||
if (key.indexOf(';') === (key.length - 1)) { | ||
key = key.substr(0, key.length - 2); | ||
} | ||
while ((r = re.exec(content))) { | ||
const attr = trim(r[1], '\'"'); | ||
const keys = (attr.indexOf(';') >= 0) | ||
? attr.split(';') | ||
: [attr]; | ||
setter(key); | ||
} | ||
keys.forEach((key) => { | ||
key = trim(key); | ||
if (key.length === 0) { | ||
return; | ||
const walk = (nodes) => { | ||
nodes.forEach(node => { | ||
if (node.attrs) { | ||
node.attrs.forEach(attr => { | ||
if (attrs.indexOf(attr.name)!==-1) { | ||
const values = attr.value.split(';'); | ||
values.forEach(parseAttributeValue); | ||
} | ||
}); | ||
} | ||
if (key.indexOf('[') === 0) { | ||
const parts = key.split(']'); | ||
key = parts[1]; | ||
if (node.childNodes) { | ||
walk(node.childNodes); | ||
} | ||
if (key.indexOf(';') === (key.length - 1)) { | ||
key = key.substr(0, key.length - 2); | ||
} | ||
}) | ||
} | ||
if (customHandler) { | ||
customHandler(key); | ||
return; | ||
} | ||
walk(ast.childNodes) | ||
this.set(key); | ||
}); | ||
} | ||
return this; | ||
@@ -456,4 +482,4 @@ } | ||
const keys = isString(this.options.keySeparator) | ||
? key.split(this.options.keySeparator) | ||
: [key]; | ||
? key.split(this.options.keySeparator) | ||
: [key]; | ||
const lng = opts.lng | ||
@@ -460,0 +486,0 @@ ? opts.lng |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
13
610
4
92940
6
19
1662
+ Addedparse5@^3.0.2
+ Added@types/node@22.7.4(transitive)
+ Addedparse5@3.0.3(transitive)
+ Addedundici-types@6.19.8(transitive)
Updatedvinyl@^2.1.0