MEAN stack foreign language translations

For the MEAN application I’m currently building, there is a requirement to have it served in multiple user-selectable languages. I used the MEAN fullstack generator (https://github.com/DaftMonk/generator-angular-fullstack), which does not provide i18n (internationalization) support.

When setting up my application for i18n, I realized that I needed translations available up and down the stack. So not just in the View, also in the Model and Controller. I ended up using angular-translate (https://github.com/angular-translate/angular-translate) and MomentJS (https://github.com/moment/moment/) in the client side AngularJS. And I created my own custom solution, very simple, in Node for the server side model and controller.

I think angular-translate works great in Angular, and there are plenty of guides around so I won’t go into it. But I want to mention that angular-translate doesn’t have great support (at least that I could find) for translating dates and numbers. This is where MomentJS can fill in the gaps. Again, plenty of guides out and good documentation out there for MomentJS.

For Node, I created a module that simply has a JSON of all the translations, and a function that returns the translation. Example below:

—translations.js—

'use strict';
var en = {
  VERIFICATION_EMAIL_SUBJECT: 'Sign up verification',
  VERIFICATION_EMAIL_TEXT: 'You are receiving this email because you or someone else has signed up with this email address (%s)',
};
var fr = {
  VERIFICATION_EMAIL_SUBJECT: 'S\'inscrire vérification',
  VERIFICATION_EMAIL_TEXT: 'Vous recevez ce courriel parce que vous ou quelqu\'un d\'autre a signé avec cette adresse email (%s)',
};
module.exports.get = function(lang, key)
{
  if(lang == 'en')
    return en[key];
  else if(lang == 'fr')
    return fr[key];
};
module.exports.en = en;
module.exports.fr = fr;

And then then use it like so:

var translations = require('translations');
console.log(translations.get('en','VERIFICATION_EMAIL_SUBJECT'));
console.log(sprintf(translations.get(user.language,'VERIFICATION_EMAIL_TEXT'),'blah@blah.com'));

This way translations can be available anywhere on the server side that uses Node.

Correctly doing post-login processing in the DaftMonk AngularJS full-stack seed

So I’ve been working on a personal project using the MEAN stack (MongoDB, ExpressJS, AngularJS and NodeJS)! The nerd in me has been pretty excited to learn something completely new and different. I’ve never done full-stack development strictly in JavaScript, and so far I’m finding it to be pretty neat. I’ll be making posts about things I struggle with, or find useful, as I progress.

Anyway, I used the DaftMonk AngularJS full-stack yeoman generator (https://github.com/DaftMonk/generator-angular-fullstack) for my project seed. I definitely recommend it if you’re starting out fresh with MEAN (or even if you’re not), since it speeds up the initial setup and development immensely.

My problem arose as I was wiring up some post-processing to be done after a user logged in. In the login controller (login.controller.js), after the login function is called from the Auth service, there is a function in “.then()” that is called upon success.

Auth.login({
  email: $scope.user.email,
  password: $scope.user.password
})
.then( function() {
    //login was successful
    //...
  }

However, even though the user has logged in, the user data is not available yet! So, you cannot access the current user’s data properties (such as their role) through Auth.getCurrentUser() (for example the Auth.getCurrentUser().role field will be undefined). This is due to the fact that the data is loaded asynchronously (I’m still trying to get the hang of how that works).

The way around this is to use the Auth.isLoggedInAsync(…callback…) function. The callback sent to isLoggedInAsync is called after the user has finally been loaded, which will guarantee your post-login-processing code being executed after the data for the user is available.

This is how you’d make use of Auth.isLoggedInAsync(…):

Auth.login({
  email: $scope.user.email,
  password: $scope.user.password
})
.then( function() {
    Auth.isLoggedInAsync(function(success) {
      //Auth.getCurrentUser() will now return the user with all the properties fully loaded
    }

Enjoy!