Angular

ngMessageFormat - Angular's unheard feature

Angular 1.5 is pretty much around the corner and with a new release, new fixes, improvements and features are added to the framework. While this is awesome and we’re all excited about it, it seems like we’re forgetting about all the nice things we already have.

tweet

A few days ago, we asked on twitter who’s interested to learn about an unheard feature in Angular. Based on the reactions to that tweet, it’s quite obvious that you all are and that’s awesome! So what is this unheard feature we’re talking about? If you read this article you can surely tell from its title that it’s probably about this thing called ngMessageFormat. We’ll get right into it but first we’d like to make one thing clear:

This feature is available since Angular 1.4

If you’re on version 1.4 or higher, this feature is already available to use. So, what you learn in the next couple of minutes you can use straight away!

Understanding Pluralization and Gender Selection

Earlier this year I gave a talk together with Chirayu, a former member of the Angular core team, about how the Angular project is going to solve internationalization and localization in the future. The talk can be watched right here and if you’re more a reader kind of person, we wrote about everything in our article on Angular and i18n - A new world.

One thing that is an essential part of i18n, but also a sort of isolated topic at the same time, is pluralization and gender selection. We probably all ran into this at a some point. For example, displaying a notification that says:

You have {{numberOfMessages}} new messages.

While this works as long as numberOfMessages evaluates to something > 1, it doesn’t fit anymore as soon as we have just a single message. Our template would look something like this:

You have 1 new messages.

This can easily be solved with the ngSwitch directive, or, in fact Angular comes with an ngPluralize directive that introduces a couple more features (like offset) to make pluralization easy. Here’s an ngPluralize solution for the scenario above:

<ng-pluralize count="numberOfMessages"
              when="{'1': 'You have one new message.',
                     'other': 'You have {} new messages.'}">
</ng-pluralize>

Pluralization can be hard, especially if we consider that it can vary heavily depending on the language we’re using. While we have “one” and “more” in most of the european language rules, other languages have “one”, “few” and “more”.

Another thing that comes into play is gender selection. Depending on a persons gender, we might need to output different text.

Send him an invite.
Send her an invite.
Send them an invite.

This can not be solved with ngPluralize today. Also, what if we have text in HTML attributes that needs to be pluralized as well?

Introducing ngMessageFormat

Luckily, there’s a standard called ICU Messageformat which tackles pluralization and gender selection properly. In fact, with Messageformat, we can even nest gender selection rules and pluralization rules and vice-versa. But what has this to do with Angular?

Well, as part of the effort for the new i18n solution, Angular’s interplation syntax got extended in Angular 1.4. In other words, we can basically overload the expression syntax with ICU Messageformat expressions. All we have to do is to include the ngMessageFormat module.

ngMessageFormat can be installed via npm using the following command:

$ npm install angular-message-format

Once installed and included in our HTML document, we can add it as a module dependency and start using it right away!

angular.module('myApp', ['ngMessageFormat']);

Pluralization with ngMessageFormat

With ngMessageFormat included, we can overload Angular expressions using a comma like this:

{{EXPRESSION, TYPE,
     =VALUE { MESSAGE }
     ...
}}

Whereas EXPRESSION is the expression that needs to be evaluated, TYPE specifies what we want to do plural or select for pluralization and gender selection respectively. Let’s use this syntax to output our notification, based on numberOfMessages.

{{numberOfMessages, plural,
    =0 { You have no new messages }
    =1 { You have one new message }
    other { You have # new messages }
}}

As we can see, # can be used as a placeholder that gets replaced with the actual evaluated value. Another nice thing to notice: We can use still use Angular expressions and filters inside those messages!

Gender selection with ngMessageFormat

Gender selection uses the exact same syntax. All we have to do is to change the selection type and define messages for each gender:

{{genderExpression, select,
    male { Send him a message. }
    female { Send her a message. }
    other { Send them a message. }
}}

Conclusion

Unfortunately ngMessageFormat is not very well documented and it didn’t get a lot of love after it has been released. However, it is right there and it wants to be used. Just remember that it allows you to pluralize not only HTML attributes, it even makes nesting of plural and gender selection possible!

Written by  Author

Pascal Precht