Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

i18next-parser

Package Overview
Dependencies
Maintainers
1
Versions
144
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

i18next-parser - npm Package Compare versions

Comparing version 1.0.0-beta23 to 1.0.0-beta26

46

bin/cli.js

@@ -15,3 +15,3 @@ #!/usr/bin/env node

.option('-c, --config <path>', 'Path to the config file (default: i18next-scanner.config.js)')
.option('-o, --output <path>', 'Path to the output directory (default: locales)')
.option('-o, --output <path>', 'Path to the output directory (default: locales/$LOCALE/$NAMESPACE.json)')
.option('-s, --silent', 'Disable logging to stdout')

@@ -24,3 +24,3 @@

console.log(' $ i18next "/path/to/src/app.js" "/path/to/assets/index.html"')
console.log(' $ i18next --config i18next-parser.config.js --output /path/to/output \'src/**/*.{js,jsx}\'')
console.log(' $ i18next --config i18next-parser.config.js --output locales/$LOCALE/$NAMESPACE.json')
console.log('')

@@ -31,12 +31,2 @@ })

var args = program.args || []
var globs = args.map(function (s) {
s = s.trim()
if (s.match(/(^'.*'$|^".*"$)/)) {
s = s.slice(1, -1)
}
return s
})
var config = {}

@@ -54,2 +44,34 @@ if (program.config) {

var args = program.args || []
var globs
// prefer globs specified in the cli
if (args.length) {
globs = args.map(function (s) {
s = s.trim()
if (s.match(/(^'.*'$|^".*"$)/)) {
s = s.slice(1, -1)
}
return s
})
}
// if config has an input parameter, try to use it
else if (config.input) {
if (!Array.isArray(config.input)) {
if (typeof config.input === 'string') {
config.input = [config.input]
}
else {
console.log(' [error] '.red + '`input` must be an array when specified in the config')
program.help()
program.exit(1)
}
}
globs = config.input.map(function (s) {
return path.resolve(path.dirname(path.resolve(program.config)), s)
})
}
if (!output) {

@@ -56,0 +78,0 @@ console.log(' [error] '.red + 'an `output` is required via --config or --output option')

@@ -25,4 +25,2 @@ 'use strict';Object.defineProperty(exports, "__esModule", { value: true });var _extends = Object.assign || function (target) {for (var i = 1; i < arguments.length; i++) {var source = arguments[i];for (var key in source) {if (Object.prototype.hasOwnProperty.call(source, key)) {target[key] = source[key];}}}return target;};var _createClass = function () {function defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}return function (Constructor, protoProps, staticProps) {if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;};}();var _helpers = require('./helpers');

defaultValue: '',
extension: '.json',
filename: '$NAMESPACE',
indentation: 2,

@@ -35,3 +33,3 @@ keepRemoved: false,

namespaceSeparator: ':',
output: 'locales',
output: 'locales/$LOCALE/$NAMESPACE.json',
reactNamespace: false,

@@ -136,19 +134,13 @@ sort: false,

for (var _iterator3 = this.options.locales[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {var locale = _step3.value;
var outputPath = _path2.default.resolve(this.options.output, locale);
var outputPath = _path2.default.resolve(this.options.output);
for (var namespace in catalog) {
var filename = this.options.filename;
filename = filename.replace(this.localeRegex, locale);
filename = filename.replace(this.namespaceRegex, namespace);
var namespacePath = outputPath;
namespacePath = namespacePath.replace(this.localeRegex, locale);
namespacePath = namespacePath.replace(this.namespaceRegex, namespace);
var extension = this.options.extension;
extension = extension.replace(this.localeRegex, locale);
extension = extension.replace(this.namespaceRegex, namespace);
var parsedNamespacePath = _path2.default.parse(namespacePath);
var oldFilename = filename + '_old' + extension;
filename += extension;
var namespaceOldPath = _path2.default.join(parsedNamespacePath.dir, parsedNamespacePath.name + '_old' + parsedNamespacePath.ext);
var namespacePath = _path2.default.resolve(outputPath, filename);
var namespaceOldPath = _path2.default.resolve(outputPath, oldFilename);
var existingCatalog = this.getCatalog(namespacePath);

@@ -155,0 +147,0 @@ var existingOldCatalog = this.getCatalog(namespaceOldPath);

@@ -7,9 +7,9 @@ # Examples

`i18next /path/to/file/or/dir -o /output/directory`
`i18next /path/to/file/or/dir -o /translations/$LOCALE/$NAMESPACE.json`
`i18next /path/to/file/or/dir:/output/directory`
`i18next /path/to/file/or/dir:/translations/$LOCALE/$NAMESPACE.json`
Gulp:
`.pipe(i18next({output: 'translations'}))`
`.pipe(i18next({output: 'translations/$LOCALE/$NAMESPACE.json'}))`

@@ -19,3 +19,3 @@ It will create the file in the specified folder (in case of gulp it doesn't actually create the files until you call `dest()`):

```
/output/directory/en/translation.json
/translations/en/translation.json
...

@@ -153,8 +153,6 @@ ```

`.pipe(i18next({
output: "i18n",
output: "i18n/$LOCALE/$NAMESPACE.$LOCALE.i18n.json",
locales: ['en', 'de', 'fr', 'es'],
functions: ['_'],
namespace: 'client',
suffix: '.$LOCALE',
extension: ".i18n.json",
writeOld: false

@@ -161,0 +159,0 @@ }))`

@@ -10,4 +10,6 @@ # Migrating from `0.x` to `1.x`

- `namespace` was renamed `defaultNamespace`. It defaults to `translation`.
- `prefix` was deprecated. Use `filename`
- `suffix` was deprecated. Use `filename`
- `prefix` was deprecated. Use `output`
- `suffix` was deprecated. Use `output`
- `filename` was deprecated. Use `output`
- `extension` was deprecated. Use `output`
- catalogs are no longer sorted by default. Set `sort` to `true` to enable this.

@@ -18,3 +20,3 @@

- `defaultValue`: replace empty keys with the given value
- `filename` and `extension` support for `$NAMESPACE` and `$LOCALE` variables
- `output` support for `$NAMESPACE` and `$LOCALE` variables
- `indentation` let you control the indentation of the catalogs

@@ -21,0 +23,0 @@ - `lineEnding` let you control the line ending of the catalogs

module.exports = {
output: 'test/manual'
output: 'test/manual/$LOCALE/$NAMESPACE.json'
};

@@ -18,3 +18,3 @@ - Is this a bug or a feature request?

locales: ['en', 'de'],
output: '../locales'
output: 'locales/$LOCALE/$NAMESPACE.json'
}

@@ -21,0 +21,0 @@ ```

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

"name": "i18next-parser",
"version": "1.0.0-beta23",
"version": "1.0.0-beta26",
"license": "MIT",

@@ -8,0 +8,0 @@ "main": "dist/index.js",

@@ -7,4 +7,9 @@ # i18next Parser [![Build Status](https://travis-ci.org/i18next/i18next-parser.svg?branch=master)](https://travis-ci.org/i18next/i18next-parser)

If you want to make this process even less painful, I invite you to check [Locize](https://locize.com/). And if you use this package and like it, supporting me on [Patreon](https://www.patreon.com/karelledru) would mean a great deal! (disclamer: Locize is supporting this project on Patreon).
Finally, if you want to make this process even less painful, I invite you to check [Locize](https://locize.com/). They are a sponsor of this project. Actually, if you use this package and like it, supporting me on [Patreon](https://www.patreon.com/karelledru) would mean a great deal!
<p>
<a href="https://www.patreon.com/karelledru" target="_blank">
<img src="https://c5.patreon.com/external/logo/become_a_patron_button.png" alt="Become a Patreon">
</a>
</p>

@@ -64,3 +69,3 @@ ## Features

locales: ['en', 'de'],
output: 'locales'
output: 'locales/$LOCALE/$NAMESPACE.json'
}))

@@ -97,3 +102,3 @@ .pipe(gulp.dest('./'));

i18n = new i18nextParser([i18n], {
output: 'broccoli/locales'
output: 'broccoli/locales/$LOCALE/$NAMESPACE.json'
})

@@ -106,33 +111,31 @@

Option | Description | Default
---------------------- | ----------------------------------------------------- | ---
**contextSeparator** | Key separator used in your translation keys | `_`
**createOldCatalogs** | Save the \_old files | `true`
**defaultNamespace** | Default namespace used in your i18next config | `translation`
**defaultValue** | Default value to give to empty keys | `''`
**extension** <sup>1<sup>| Extenstion of the catalogs | `.json`
**filename** <sup>1<sup>| Filename of the catalogs | `'$NAMESPACE'`
**indentation** | Indentation of the catalog files | `2`
**keepRemoved** | Keep keys from the catalog that are no longer in code | `false`
**keySeparator** <sup>2<sup>| Key separator used in your translation keys | `.`
**lexers** | See below for details | `{}`
**lineEnding** | Control the line ending. See options at [eol](https://github.com/ryanve/eol) | `auto`
**locales** | An array of the locales in your applications | `['en','fr']`
**namespaceSeparator** <sup>2<sup>| Namespace separator used in your translation keys | `:`
**output** | Where to write the locale files relative to the base | `locales`
**reactNamespace** <sup>3<sup>| For react file, extract the [defaultNamespace](https://react.i18next.com/components/translate-hoc.html) | `false`
**sort** | Whether or not to sort the catalog | `false`
**verbose** | Display info about the parsing including some stats | `false`
Using a config file gives you fine-grained control over how i18next-parser treats your files. Here's an example config showing all config options with their defaults.
1. Both `filename` and `extension` options support injection of `$LOCALE` and `$NAMESPACE` variables. The file output is JSON by default, if you want YAML, the `extension` must end with `yml`.
2. If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance.
3. If the file being parsed has a `.jsx` extension, this option is ignored and the namespace is being extracted.
```js
// i18next-parser.config.js
module.exports = {
contextSeparator: '_',
// Key separator used in your translation keys
### Lexers
createOldCatalogs: true,
// Save the \_old files
The `lexers` option let you configure which Lexer to use for which extension. Here is the default:
defaultNamespace: 'translation',
// Default namespace used in your i18next config
```js
{
defaultValue: '',
// Default value to give to empty keys
indentation: 2,
// Indentation of the catalog files
keepRemoved: false,
// Keep keys from the catalog that are no longer in code
keySeparator: '.',
// Key separator used in your translation keys
// If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance.
// see below for more details
lexers: {

@@ -145,67 +148,95 @@ hbs: ['HandlebarsLexer'],

js: ['JavascriptLexer'],
jsx: ['JavascriptLexer', 'JsxLexer'],
js: ['JavascriptLexer'], // if you're writing jsx inside .js files, change this to JsxLexer
jsx: ['JsxLexer'],
mjs: ['JavascriptLexer'],
default: ['JavascriptLexer']
}
}
```
},
Note the presence of a `default` which will catch any extension that is not listed. There are 3 lexers available: `HandlebarsLexer`, `HTMLLexer` and `JavascriptLexer`. Each has configurations of its own. If you need to change the defaults, you can do it like so:
lineEnding: 'auto',
// Control the line ending. See options at https://github.com/ryanve/eol
```js
{
lexers: {
hbs: [
{
lexer: 'HandlebarsLexer',
functions: ['translate', '__']
}
],
js: [
{
lexer: 'JavascriptLexer',
acorn: {
plugins: {
jsx: true,
objectRestSpread: true,
es7: true
}
}
}
]
// ...
}
locales: ['en', 'fr'],
// An array of the locales in your applications
namespaceSeparator: ':',
// Namespace separator used in your translation keys
// If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance.
output: 'locales/$LOCALE/$NAMESPACE.json',
// Supports $LOCALE and $NAMESPACE injection
// Where to write the locale files relative to the base
input: undefined,
// An array of globs that describe where to look for source files
reactNamespace: false,
// For react file, extract the defaultNamespace - https://react.i18next.com/components/translate-hoc.html
// Ignored when parsing a `.jsx` file and namespace is extracted from that file.
sort: false,
// Whether or not to sort the catalog
verbose: false
// Display info about the parsing including some stats
}
```
**`HandlebarsLexer` options**
### Lexers
Option | Description | Default
------------- | --------------------------- | -------
**functions** | Array of functions to match | `['t']`
The `lexers` option let you configure which Lexer to use for which extension. Here is the default:
**`HTMLLexer` options**
Note the presence of a `default` which will catch any extension that is not listed. There are 3 lexers available: `HandlebarsLexer`, `HTMLLexer` and `JavascriptLexer`. Each has configurations of its own. If you need to change the defaults, you can do it like so:
Option | Description | Default
-------------- | --------------------------- | -------
**attr** | Attribute for the keys | `'data-i18n'`
**optionAttr** | Attribute for the options | `'data-i18n-options'`
```js
[
// HandlebarsLexer default config (hbs, handlebars)
handlebars: [{
lexer: 'HandlebarsLexer',
functions: ['t'] // Array of functions to match
}]
**`JavscriptLexer` options**
// HtmlLexer default config (htm, html)
html: [{
lexer: 'HtmlLexer',
attr: 'data-i18n' // Attribute for the keys
optionAttr: 'data-i18n-options' // Attribute for the options
}]
Option | Description | Default
------------- | --------------------------- | -------
**functions** | Array of functions to match | `['t']`
**acorn** | Options to pass to acorn | `{}`
// JavascriptLexer default config (js, mjs)
js: [{
lexer: 'JavascriptLexer'
functions: ['t'], // Array of functions to match
**`JsxLexer` options**
// acorn config (for more information on the acorn options, see here: https://github.com/acornjs/acorn#main-parser)
acorn: {
sourceType: 'module',
ecmaVersion: 9, // forward compatibility
plugins: {
es7: true, // some es7 parsing that's not yet in acorn (decorators)
stage3: true // load some stage3 configs not yet in a version
}
}
}],
Option | Description | Default
------------- | ---------------------- | -------
**attr** | Attribute for the keys | `i18nKey`
// JsxLexer default config (jsx)
// JsxLexer can take all the options of the JavascriptLexer plus the following
jsx: [{
lexer: 'JsxLexer',
attr: 'i18nKey', // Attribute for the keys
// acorn config (for more information on the acorn options, see here: https://github.com/acornjs/acorn#main-parser)
acorn: {
sourceType: 'module',
ecmaVersion: 9, // forward compatibility
plugins: {
es7: true, // some es7 parsing that's not yet in acorn (decorators)
stage3: true, // load some stage3 configs not yet in a version
jsx: true // always defaults to true in .jsx files
}
}
}]
]
```
## Events

@@ -232,1 +263,19 @@

Thanks a lot to all the previous [contributors](https://github.com/i18next/i18next-parser/graphs/contributors).
If you use this package and like it, supporting me on [Patreon](https://www.patreon.com/karelledru) is another great way to contribute!
<p>
<a href="https://www.patreon.com/karelledru" target="_blank">
<img src="https://c5.patreon.com/external/logo/become_a_patron_button.png" alt="Become a Patreon">
</a>
</p>
--------------
## Gold Sponsors
<p>
<a href="https://locize.com/" target="_blank">
<img src="https://raw.githubusercontent.com/i18next/i18next/master/assets/locize_sponsor_240.gif" width="240px">
</a>
</p>

@@ -25,4 +25,2 @@ import { dotPathToHash, mergeHashes, transferValues } from './helpers'

defaultValue: '',
extension: '.json',
filename: '$NAMESPACE',
indentation: 2,

@@ -35,3 +33,3 @@ keepRemoved: false,

namespaceSeparator: ':',
output: 'locales',
output: 'locales/$LOCALE/$NAMESPACE.json',
reactNamespace: false,

@@ -136,19 +134,13 @@ sort: false,

for (const locale of this.options.locales) {
const outputPath = path.resolve(this.options.output, locale)
const outputPath = path.resolve(this.options.output)
for (const namespace in catalog) {
let filename = this.options.filename
filename = filename.replace(this.localeRegex, locale)
filename = filename.replace(this.namespaceRegex, namespace)
let namespacePath = outputPath
namespacePath = namespacePath.replace(this.localeRegex, locale)
namespacePath = namespacePath.replace(this.namespaceRegex, namespace)
let extension = this.options.extension
extension = extension.replace(this.localeRegex, locale)
extension = extension.replace(this.namespaceRegex, namespace)
let parsedNamespacePath = path.parse(namespacePath)
const oldFilename = filename + '_old' + extension
filename += extension
const namespaceOldPath = path.join(parsedNamespacePath.dir, `${parsedNamespacePath.name}_old${parsedNamespacePath.ext}`)
const namespacePath = path.resolve(outputPath, filename)
const namespaceOldPath = path.resolve(outputPath, oldFilename)
let existingCatalog = this.getCatalog(namespacePath)

@@ -155,0 +147,0 @@ let existingOldCatalog = this.getCatalog(namespaceOldPath)

@@ -12,5 +12,5 @@ const Funnel = require('broccoli-funnel')

i18n = new i18nextParser([i18n], {
output: 'broccoli/locales'
output: 'broccoli/locales/$LOCALE/$NAMESPACE.json'
})
module.exports = i18n

@@ -8,5 +8,5 @@ const gulp = require('gulp');

locales: ['en', 'fr'],
output: 'gulp/locales'
output: 'gulp/locales/$LOCALE/$NAMESPACE.json'
}))
.pipe(gulp.dest('./'));
});
module.exports = {
output: 'manual'
output: 'manual/$LOCALE/$NAMESPACE.json'
};

@@ -320,3 +320,3 @@ import { assert } from 'chai'

let result, resultOld
const i18nextParser = new i18nTransform({ output: 'test/locales' })
const i18nextParser = new i18nTransform({ output: 'test/locales/$LOCALE/$NAMESPACE.json' })
const fakeFile = new Vinyl({

@@ -347,3 +347,3 @@ contents: Buffer.from("t('test_merge:first'); t('test_merge:second')"),

let resultFR
const i18nextParser = new i18nTransform({ output: 'test/locales' })
const i18nextParser = new i18nTransform({ output: 'test/locales/$LOCALE/$NAMESPACE.json' })
const fakeFile = new Vinyl({

@@ -373,3 +373,3 @@ contents: Buffer.from("t('test_leak:first'); t('test_leak:second')"),

let result
const i18nextParser = new i18nTransform({ output: 'test/locales' })
const i18nextParser = new i18nTransform({ output: 'test/locales/$LOCALE/$NAMESPACE.json' })
const fakeFile = new Vinyl({

@@ -400,3 +400,3 @@ contents: Buffer.from("t('test_context:first')"),

it('saves unused translations in the old catalog', (done) => {
const i18nextParser = new i18nTransform({ output: 'test/locales' })
const i18nextParser = new i18nTransform({ output: 'test/locales/$LOCALE/$NAMESPACE.json' })
const fakeFile = new Vinyl({

@@ -429,3 +429,3 @@ contents: Buffer.from("t('test_old:parent.third', 'third'), t('test_old:fourth', 'fourth')"),

it('restores translations from the old catalog', (done) => {
const i18nextParser = new i18nTransform({ output: 'test/locales' })
const i18nextParser = new i18nTransform({ output: 'test/locales/$LOCALE/$NAMESPACE.json' })
const fakeFile = new Vinyl({

@@ -459,3 +459,3 @@ contents: Buffer.from("t('test_old:parent.some', 'random'), t('test_old:other', 'random')"),

let result
const i18nextParser = new i18nTransform({ output: 'test/locales' })
const i18nextParser = new i18nTransform({ output: 'test/locales/$LOCALE/$NAMESPACE.json' })
const fakeFile = new Vinyl({

@@ -491,3 +491,3 @@ contents: Buffer.from(

let result
const i18nextParser = new i18nTransform({ output: 'test/locales' })
const i18nextParser = new i18nTransform({ output: 'test/locales/$LOCALE/$NAMESPACE.json' })
const fakeFile = new Vinyl({

@@ -518,3 +518,3 @@ contents: Buffer.from("t('test_context_plural:first')"),

describe('options', () => {
it('handles filename and extension with $LOCALE and $NAMESPACE var', (done) => {
it('handles output with $LOCALE and $NAMESPACE var', (done) => {
let result

@@ -524,4 +524,3 @@ const i18nextParser = new i18nTransform({

defaultNamespace: 'default',
filename: 'p-$LOCALE-$NAMESPACE',
extension: '.$LOCALE.i18n'
output: 'locales/$LOCALE/p-$LOCALE-$NAMESPACE.$LOCALE.i18n'
})

@@ -707,3 +706,3 @@ const fakeFile = new Vinyl({

const i18nextParser = new i18nTransform({
extension: '.yml'
output: 'locales/$LOCALE/$NAMESPACE.yml'
})

@@ -891,3 +890,3 @@ const fakeFile = new Vinyl({

it('emits a `error` event if the catalog is not valid json', (done) => {
const i18nextParser = new i18nTransform({ output: 'test/locales' })
const i18nextParser = new i18nTransform({ output: 'test/locales/$LOCALE/$NAMESPACE.json' })
const fakeFile = new Vinyl({

@@ -921,3 +920,3 @@ contents: Buffer.from("t('test_invalid:content')"),

it('emits a `warning` event if a key contains a variable', (done) => {
const i18nextParser = new i18nTransform({ output: 'test/locales' })
const i18nextParser = new i18nTransform({ output: 'test/locales/$LOCALE/$NAMESPACE.json' })
const fakeFile = new Vinyl({

@@ -936,3 +935,3 @@ contents: Buffer.from('t(variable)'),

it('emits a `warning` event if a react value contains two variables', (done) => {
const i18nextParser = new i18nTransform({ output: 'test/locales' })
const i18nextParser = new i18nTransform({ output: 'test/locales/$LOCALE/$NAMESPACE.json' })
const fakeFile = new Vinyl({

@@ -939,0 +938,0 @@ contents: Buffer.from('<Trans>{{ key1, key2 }}</Trans>'),

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