Security News
Research
Supply Chain Attack on Rspack npm Packages Injects Cryptojacking Malware
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
i18next-parser
Advanced tools
i18next-parser is a tool that extracts translation keys from your source code to JSON, allowing you to manage and maintain your internationalization (i18n) files more efficiently. It supports various file formats and can be integrated into your build process.
Extract Translation Keys
This feature allows you to extract translation keys from your source code files and generate JSON files for each locale. The code sample demonstrates how to use i18next-parser to parse JavaScript files in the 'src' directory and output the translations to 'locales/en/translation.json' and 'locales/fr/translation.json'.
const parser = require('i18next-parser');
const fs = require('fs');
const options = {
locales: ['en', 'fr'],
output: 'locales/$LOCALE/$NAMESPACE.json'
};
parser.parseFiles('src/**/*.js', options, (err, translations) => {
if (err) throw err;
fs.writeFileSync('locales/en/translation.json', JSON.stringify(translations.en, null, 2));
fs.writeFileSync('locales/fr/translation.json', JSON.stringify(translations.fr, null, 2));
});
Support for Multiple File Formats
i18next-parser supports multiple file formats including JavaScript, JSX, TypeScript, and TSX. The code sample shows how to configure the parser to handle these different file types and extract translations from them.
const parser = require('i18next-parser');
const options = {
input: ['src/**/*.js', 'src/**/*.jsx', 'src/**/*.ts', 'src/**/*.tsx'],
output: 'locales/$LOCALE/$NAMESPACE.json'
};
parser.parseFiles(options.input, options, (err, translations) => {
if (err) throw err;
console.log('Translations extracted successfully');
});
Customizable Output
You can customize the output path and separators for namespaces and keys. The code sample demonstrates how to set a custom output path and define custom separators for namespaces and keys.
const parser = require('i18next-parser');
const options = {
locales: ['en', 'de'],
output: 'custom_locales/$LOCALE/$NAMESPACE.json',
namespaceSeparator: ':',
keySeparator: '.'
};
parser.parseFiles('src/**/*.js', options, (err, translations) => {
if (err) throw err;
console.log('Custom output path and separators applied');
});
babel-plugin-i18next-extract is a Babel plugin that extracts translation keys from your code and generates JSON files for i18next. It integrates directly with Babel, making it a good choice if you are already using Babel in your project. Compared to i18next-parser, it offers a more seamless integration with the Babel build process but may require more setup if you are not using Babel.
react-intl-translations-manager is a tool for managing translations in projects using react-intl. It extracts messages from your React components and generates translation files. While it is specifically designed for use with react-intl, it offers similar functionality to i18next-parser in terms of extracting and managing translation keys. However, it is less flexible in terms of file format support and integration with non-React projects.
When translating an application, maintaining the translation catalog by hand is painful. This package parses your code and automates this process.
Finally, if you want to make this process even less painful, I invite you to check Locize. They are a sponsor of this project. Actually, if you use this package and like it, supporting me on Patreon would mean a great deal!
namespace_old.json
catalog_old
file if the one in the translation file is emptykey_context
key_plural
and key_0
, key_1
as described here1.x
has been in beta for a good while. You can follow the pre-releases here. It is a deep rewrite of this package that solves many issues, the main one being that it was slowly becoming unmaintainable. The migration from 0.x
contains all the breaking changes. Everything that follows is related to 1.x
. You can still find the old 0.x
documentation on its dedicated branch.
You can use the CLI with the package installed locally but if you want to use it from anywhere, you better install it globally:
yarn global add i18next-parser
npm install -g i18next-parser
i18next 'app/**/*.{js,hbs}' 'lib/**/*.{js,hbs}' [-oc]
Multiple globbing patterns are supported to specify complex file selections. You can learn how to write globs here. Note that glob must be wrapped with single quotes when passed as arguments.
IMPORTANT NOTE: If you pass the globs as CLI argument, they must be relative to where you run the command (aka relative to process.cwd()
). If you pass the globs via the input
option of the config file, they must be relative to the config file.
Save the package to your devDependencies:
yarn add -D i18next-parser
npm install --save-dev i18next-parser
Gulp defines itself as the streaming build system. Put simply, it is like Grunt, but performant and elegant.
const i18nextParser = require('i18next-parser').gulp;
gulp.task('i18next', function() {
gulp.src('app/**')
.pipe(new i18nextParser({
locales: ['en', 'de'],
output: 'locales/$LOCALE/$NAMESPACE.json'
}))
.pipe(gulp.dest('./'));
});
IMPORTANT: output
is required to know where to read the catalog from. You might think that gulp.dest()
is enough though it does not inform the transform where to read the existing catalog from.
Save the package to your devDependencies:
yarn add -D i18next-parser
npm install --save-dev i18next-parser
Broccoli.js defines itself as a fast, reliable asset pipeline, supporting constant-time rebuilds and compact build definitions.
const Funnel = require('broccoli-funnel')
const i18nextParser = require('i18next-parser').broccoli;
const appRoot = 'broccoli'
let i18n = new Funnel(appRoot, {
files: ['handlebars.hbs', 'javascript.js'],
annotation: 'i18next-parser'
})
i18n = new i18nextParser([i18n], {
output: 'broccoli/locales/$LOCALE/$NAMESPACE.json'
})
module.exports = i18n
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.
// i18next-parser.config.js
module.exports = {
contextSeparator: '_',
// Key separator used in your translation keys
createOldCatalogs: true,
// Save the \_old files
defaultNamespace: 'translation',
// Default namespace used in your i18next config
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: {
hbs: ['HandlebarsLexer'],
handlebars: ['HandlebarsLexer'],
htm: ['HTMLLexer'],
html: ['HTMLLexer'],
mjs: ['JavascriptLexer'],
js: ['JavascriptLexer'], // if you're writing jsx inside .js files, change this to JsxLexer
ts: ['JavascriptLexer'],
jsx: ['JsxLexer'],
tsx: ['JsxLexer'],
default: ['JavascriptLexer']
},
lineEnding: 'auto',
// Control the line ending. See options at https://github.com/ryanve/eol
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
// Supports JSON (.json) and YAML (.yml) file formats
// Where to write the locale files relative to process.cwd()
input: undefined,
// An array of globs that describe where to look for source files
// relative to the location of the configuration file
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
useKeysAsDefaultValue: false,
// Whether to use the keys as the default value; ex. "Hello": "Hello", "World": "World"
// The option `defaultValue` will not work if this is set to true
verbose: false
// Display info about the parsing including some stats
}
The lexers
option let you configure which Lexer to use for which extension. Here is the default:
Note the presence of a default
which will catch any extension that is not listed.
There are 4 lexers available: HandlebarsLexer
, HTMLLexer
, JavascriptLexer
and
JsxLexer
. Each has configurations of its own. Typescript is supported via JavascriptLexer
and JsxLexer
.
If you need to change the defaults, you can do it like so:
The Javascript lexer uses Acorn to walk through your code and extract references
translation functions. If your code uses features not supported natively by Acorn, you can enable support through
injectors
and plugins
configuration. Note that you must install these additional dependencies yourself through
yarn
or npm
; they are not included in this package. This is an example configuration that adds all non-jsx plugins supported by acorn
at the time of writing:
const injectAcornStaticClassPropertyInitializer = require('acorn-static-class-property-initializer/inject');
const injectAcornStage3 = require('acorn-stage3/inject');
const injectAcornEs7 = require('acorn-es7');
// ...
js: [{
lexer: 'JavascriptLexer'
functions: ['t'], // Array of functions to match
// acorn config (for more information on the acorn options, see here: https://github.com/acornjs/acorn#main-parser)
acorn: {
injectors: [
injectAcornStaticClassPropertyInitializer,
injectAcornStage3,
injectAcornEs7,
],
plugins: {
// The presence of these plugin options is important -
// without them, the plugins will be available but not
// enabled.
staticClassPropertyInitializer: true,
stage3: true,
es7: true,
}
}
}],
// ...
If you receive an error that looks like this:
TypeError: baseVisitor[type] is not a function
# rest of stack trace...
The problem is likely that you are missing a plugin that supports a feature that your code uses.
The default configuration is below:
{
// JavascriptLexer default config (js, mjs)
js: [{
lexer: 'JavascriptLexer'
functions: ['t'], // Array of functions to match
// 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
// Allows additional acorn plugins via the exported injector functions
injectors: [],
plugins: {},
}
}],
}
The JSX lexer builds off of the Javascript lexer, and additionally requires the acorn-jsx
plugin. To use it, add acorn-jsx
to your dev dependencies:
npm install -D acorn-jsx
# or
yarn add -D acorn-jsx@4.1.1
Default configuration:
{
// 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
injectors: [],
plugins: {},
}
}],
}
Typescript is supported via Javascript and Jsx lexers. If you are using Javascript syntax (e.g. with React), follow the steps in Jsx section, otherwise Javascript section.
{
// HandlebarsLexer default config (hbs, handlebars)
handlebars: [{
lexer: 'HandlebarsLexer',
functions: ['t'] // Array of functions to match
}]
}
{
// HtmlLexer default config (htm, html)
html: [{
lexer: 'HtmlLexer',
attr: 'data-i18n' // Attribute for the keys
optionAttr: 'data-i18n-options' // Attribute for the options
}]
}
The transform emits a reading
event for each file it parses:
.pipe( i18next().on('reading', (file) => {}) )
The transform emits a error:json
event if the JSON.parse on json files fail:
.pipe( i18next().on('error:json', (path, error) => {}) )
The transform emits a warning:variable
event if the file has a key that contains a variable:
.pipe( i18next().on('warning:variable', (path, key) => {}) )
Any contribution is welcome. Please read the guidelines first.
Thanks a lot to all the previous contributors.
If you use this package and like it, supporting me on Patreon is another great way to contribute!
FAQs
Command Line tool for i18next
The npm package i18next-parser receives a total of 215,102 weekly downloads. As such, i18next-parser popularity was classified as popular.
We found that i18next-parser demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.
Security News
Sonar’s acquisition of Tidelift highlights a growing industry shift toward sustainable open source funding, addressing maintainer burnout and critical software dependencies.