/grunt-xgettext

Grunt xgettext plugin for JavaScript and Handlebars

Primary LanguageJavaScriptMIT LicenseMIT

grunt-xgettext

Grunt xgettext plugin for JavaScript, HTML and Handlebars

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 HTML and 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, use the po2json from the grunt-po2json plugin 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.5

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-xgettext --save-dev

Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

grunt.loadNpmTasks('grunt-xgettext');

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 follower" "You have %1 followers" numFollowers}}

In both cases, all string arguments inside the {{tr ...}} invocation are extracted as translatable messages.

files.html

HTML 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 follower" "You have %1 followers" numFollowers)

In both cases, all string arguments inside the tr() invocation are extracted as translatable messages.

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 with JavaScript files. Example:

tr("This is the first line " +
   "of a multiline translatable message")

Context and Comments

Finally, you can pass context and comments for your messages by using an options object. Examples:

tr("September", { comment: "Translators: use all lower-case if months are not " +
                           "capitalized in your language" })

tr("May")
tr("May", { context: "Abbreviation", comment: "Abbreviation of May" })
tr("September")
tr("Sept.", { context: "Abbreviation", comment: "Abbreviation of September" })

For Handlebars templates, you can achieve the same effect through named arguments:

{{tr "May" context="Abbreviation" comment="Abbreviation of May"}}

For JavaScript, you can also use triple-slash comments to provide translator comment:

/// Translators: use all lower-case if months are not capitalized in your language
tr("September")

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: {
      src: ["translations/*.po"],
      dest: ["translations/"],
      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

0.3.5

  • Added Underscore templates extractor.

0.3.4

  • Bugfixes for multi-line translator comments.

0.3.3

  • Introduced support for triple-slash translator comments in JavaScript extractor.

0.3.2

  • Introduced new Handlebars extractor, with support for context and comment options.
  • Bugfixes for JavaScript extractor.

0.3.1

  • Bugfixes for JavaScript extractor.

0.3.0

  • Introduced new JavaScript extractor, with support for context and comment options.