grunt-gettext
v0.1.1
Published
Gettext for JavaScript and Grunt.js
Downloads
43
Readme
grunt-gettext
Gettext for JavaScript and Grunt.js
Introduction
Gettext is the name of a set of utilities developed by GNU to add multi-language support to applications.
The first step of the translation process is to extract translatable messages from your sources.
To do so, you should mark all strings which you want to translate by wrapping them in a
translator function (often called tr()
or i18n()
). The xgettext task provided by this
plugin then scans all your source files and generates a POT file containing all the translatable
strings. In addition to scanning plain JavaScript files, this plugin also supports scanning
Handlebars templates.
The second step is converting the POT file into a PO file which is the file that will be actually
translated by translators. During this step you can merge the POT file with a previously
translated PO file resulting in a new PO file that has all known translations already filled in.
This step can be performed using the msgmerge
command-line utility. It is not provided by this
plugin, but an example of calling the utility through the Grunt Shell plugin is given below as
part of the real-world example.
The third step is taking the translated PO files and getting the translations to show up in your
project. In order to facilitate this, this plugin provides the po2json task which converts the
translations to a JSON map, optionally wrapped in a Require.js definition. To finish this step,
you will have to make sure the JSON translations are loaded into your application and actually
used by the tr()
or i18n()
function you use.
Happy translating!
To find more information about the original gettext utilities, visit the GNU project: http://www.gnu.org/software/gettext/
GNU also maintains a list of additional tools to work with PO files, including translation programs useful for translators: http://www.gnu.org/software/trans-coord/manual/web-trans/html_node/PO-Files.html
Getting Started
This plugin requires Grunt ~0.4.1
If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
npm install grunt-gettext --save-dev
Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
grunt.loadNpmTasks('grunt-gettext');
The "xgettext" task
Overview
In your project's Gruntfile, add a section named xgettext
to the data object passed into
grunt.initConfig()
.
grunt.initConfig({
xgettext: {
options: {
functionName: "tr",
potFile: "messages.pot",
//processMessage: function(message) { ... }
},
target: {
files: {
handlebars: [],
javascript: []
}
}
},
})
Options
options.functionName
Type: String
Default value: "tr"
The function name that marks translatable messages.
options.potFile
Type: String
Default value: "messages.pot"
The .pot file that is generated by this task (the output file). It will contain all extracted messages, regardless of the source in which they were found (be it Handlebars or JavaScript files).
Warning: This file is overwritten every time you run this task.
options.processMessage
Type: Function
Default value: _.identity
Custom function that will process every extracted message before it's included in the POT file. This may come in handy, for example, if you want to simplify whitespace.
The function takes the message string as its sole argument and should return the processed message.
Files
files.handlebars
Handlebars files to scan for translatable messages.
Assuming the default functionName is used, translatable messages look like this:
{{tr "Some translatable message"}}
{{tr "You have %1 followers" numFollowers}}
In either case, the first string argument is extracted as a translatable message.
files.javascript
JavaScript files to scan for translatable texts.
Assuming the default functionName is used, translatable messages look like this:
tr("Some translatable messages")
tr("You have %1 follower", "You have %1 followers").arg(numFollowers)
In both cases, all string arguments inside the tr() function call are extracted as translatable messages.
Be aware that concatenating translatable strings with variables is inherently not possible. For example, this will NOT work:
tr("Some value: " + value)
The reason this fails is because the input to the tr() function will be different every time it is called, and therefore does not have a stable key for looking up the proper translation.
Note that concatenating multiple strings to create a single (multi-line) translatable string does work, provided all parts use the same type of quotes. Example:
tr("This is the first line " +
"of a multiline translatable message")
The "po2json" task
Overview
In your project's Gruntfile, add a section named po2json
to the data object passed into
grunt.initConfig()
.
grunt.initConfig({
xgettext: {
options: {
requireJs: false
},
your_target: {
// target-specific file lists and/or options go here.
},
},
})
Options
options.requireJs
Type: Boolean
Default value: false
If set to true, the JSON resource is wrapped in an anonymouse Require.js definition.
Usage Examples
Real-world example
var _ = grunt.util._;
var locales = ["de-DE", "en-GB", "en-US", "fr-FR", "it-IT", "ja-JP", "nl-NL"];
grunt.initConfig({
xgettext: {
target: {
files: {
handlebars: ["tmpl/**.handlebars"],
javascript: ["js/**.js"]
},
options: {
functionName: "i18n",
potFile: "translations/messages.pot",
processMessage: function(message) {
return message.replace(/\s+/g, " "); // simplify whitespace
}
}
}
},
po2json: {
target: {
files: _.object(
_.map(locales, function(locale) { return "translations/" + locale + ".js"; }),
_.map(locales, function(locale) { return "translations/" + locale + ".po"; })
)
},
options: {
requireJs: true
}
}
},
shell: {
options: {
failOnError: true
},
msgmerge: {
command: _.map(locales, function(locale) {
var po = "translations/" + locale + ".po";
return "if [ -f \"" + po + "\" ]; then\n" +
" echo \"Updating " + po + "\"\n" +
" msgmerge " + po + " translations/messages.pot > .new.po.tmp\n" +
" exitCode=$?\n" +
" if [ $exitCode -ne 0 ]; then\n" +
" echo \"Msgmerge failed with exit code $?\"\n" +
" exit $exitCode\n" +
" fi\n" +
" mv .new.po.tmp " + po + "\n" +
"fi\n";
}).join("")
}
}
}
Contributing
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using Grunt.
Release History
(Nothing yet)