Using gulp to compile .po files to json for e.g. AngularJS $translate

Veröffentlicht von

If you need to deal with multiple languages in the web, there is no way around gettext. you can recognise a project using gettext, if its locale files consist of .po files and most of the time one .pot (gettext template file) which is the basefile for all language keys and the origin translation. .po fines are fine to handle as most translation agencies are able to work with them as they are easy to handle.

But if you want to use gettext files in your javascript web project, there are further steps needed to use them. The best way is to include it in your build process and which lets it run automatically upon change and get a json file out of it, which can be consumed with AngularJS $translate’s static file loader.

In my case this is gulp, the famous taskrunner. but also grunt has the same functionality (also via plugin) in place.
You should have node and gulp already set up for your project, we’re starting from there on.

Installing dependencies and configuring gulpfile.js to compile po files

Create your .po locale files

I have used PoEdit to create my files, saving them in a subdirectory ´src/locales/locale-en.po´.
You might also use this sample data for your first steps:

msgid ""
msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);n"
"Project-Id-Version: Sample Projectn"
"POT-Creation-Date: n"
"PO-Revision-Date: n"
"Last-Translator: n"
"Language-Team: n"
"MIME-Version: 1.0n"
"Content-Type: text/plain; charset=iso-8859-1n"
"Content-Transfer-Encoding: 8bitn"
"Language: enn"
"X-Generator: Poedit 1.7.6n"

msgid "COMMON.CANCEL"
msgstr "Cancel"

msgid "COMMON.OK"
msgstr "OK"

msgid "AUTH.SIGN_IN"
msgstr "Sign In"

msgid "AUTH.SIGN_UP"
msgstr "Register Account"

Install dependencies:

npm install --save-dev gulp-po-json
npm install --save-dev gulp-json-editor

Create task in gulpfile.js:

In my case the data coming our of gulp-po-json didn’t fit directly to be used for AngularJS, thats why I need jsonEditor to transform the converted data.
This is because I am grouping my locales as you can see in the sample – using a describer, a dot and the key itself ( AUTH.SIGN_IN, COMMON.OK ). I think this is a good practise to easily find module related locales.

var pojson = require('gulp-po-json');
var jsonEditor = require('gulp-json-editor');

gulp.task('translate', function() {
  return gulp.src('src/locales/*.po')
  .pipe(pojson())
  .pipe(jsonEditor(function(json){
  var ret = {},
  key,
  keySplit;
  for(key in json.dic){
    keySplit = key.split('.');
    if(!ret[keySplit[0]]) { ret[keySplit[0]] = {}; }
    ret[keySplit[0]][keySplit[1]] = (json.dic[key]) ? json.dic[key] : '';
  }
  return ret;
  }))
  .pipe(gulp.dest('build/locales/'));
});

If you run this task with ´gulp translate´, the outcome should look like that:

{
  "COMMON": {
    "CANCEL": "Cancel",
    "OK": "OK",
    "SIGN_IN": "Sign In",
    "SIGN_UP": "Register Account"
  }
}

Pretty nice, huh 🙂

Until now, this can used with any framework out there (but using java, php, ruby, I would rather go and work directly with the po, since there are classes for that).

AngularJS + static locale json

If you haven’t used $translate yet, you might have a look at bower, or use the cdn.
Bower:

bower install --save angular-translate
bower install --save angular-translate-loader-static-files

Or include those two via cdn:
http://cdnjs.com/libraries/bower-angular-translate

Using it with pascalprecht.translate

'use strict';
angular.module('myApp.i18n', ['pascalprecht.translate'])
.config(['$translateProvider', function ($translateProvider) {
        $translateProvider
            .useStaticFilesLoader({
                prefix: 'locales/locale-',
                suffix: '.json',
                key: 'dic'
            })
            .registerAvailableLanguageKeys(['en', 'de'], {
                'en_*': 'en',
                'de_*': 'de',
                '*': 'en'
            })
            .fallbackLanguage('en')
            //.useLoaderCache(true)
            .determinePreferredLanguage();

        $translateProvider.useSanitizeValueStrategy('escaped');
    }]);

You are ready to use them now in your AngularJS app. More about usage of pascalprecht’s angular-translate.