Moment.js Locale Inheritance

Moment.js released version 2.12.0 a couple weeks ago, and with that came a major new feature – locale inheritance.

Defining custom locale data has been possible in Moment.js for a very long time, and it is one of the coolest features of the library.

Suppose I wanted create a locale that was specifically for mobile use, which was in French, but had shorter strings for Moment’s relative time feature. Previous to 2.12, I might have tried something like this:

moment.locale('fr-mobile', 
      {   
      relativeTime : {
          future : 'dans %s',
          past : 'il y a %s',
          s : 's',
          m : 'une m',
          mm : '%d m',
          h : 'une h',
          hh : '%d h',
          d : 'un j',
          dd : '%d j',
          M : 'un mo',
          MM : '%d mo',
          y : 'un an',
          yy : '%d ans'
      }
    });

 

With 2.11.2 and previous, the result would have been great when I called .fromNow():

moment.locale('fr-mobile');
moment().subtract(2, 'minute').fromNow()
il y a 2 m

But I would have gotten a surprise when I called .calendar():

moment.locale('fr-mobile');
moment().calendar();
Today at 10:27 PM

 

English! Whoops. This is because there was no locale inheritance in Moment.js. Locales always fell back to English if data was not defined. To create this fr-mobile locale, I would have had to define every locale property available in Moment.

Enter locale inheritance.

Now I can just define a parent locale for my mobile locale:

moment.locale('fr-mobile', 
      {  parentLocale:'fr', 
        relativeTime : {
            future : 'dans %s',
            past : 'il y a %s',
            s : 's',
            m : 'une m',
            mm : '%d m',
            h : 'une h',
            hh : '%d h',
            d : 'un j',
            dd : '%d j',
            M : 'un mo',
            MM : '%d mo',
            y : 'un an',
            yy : '%d ans'
        }
    });
    moment.locale('fr-mobile');
    moment().subtract(2, 'minute').fromNow()
    //il y a 2 m
    moment().calendar()
    //Aujourd'hui à 22:33

 

Much Better!

Previously, there was also an issue with partial object definitions. Suppose I wanted to change just a couple things about relative time in the French locale. I would have tried this:

moment.locale('fr', 
      {   
      relativeTime : {
          future : 'dans %s',
          past : 'il y a %s',
          s : 's',
          m : 'une m',
          mm : '%d m',
      }
    });
    moment.locale('fr');
    moment().subtract(2, 'minute').fromNow()
    //il y a 2 m
    moment().subtract(1, 'year').fromNow()
    //Uncaught TypeError: Cannot read property 'replace' of undefined

That didn’t go well did it?

Enter updateLocale in 2.12.

moment.updateLocale('fr', 
      { 
      relativeTime : {
          future : 'dans %s',
          past : 'il y a %s',
          s : 's',
          m : 'une m',
          mm : '%d m',
      }
    });
    moment.locale('fr');
    moment().subtract(2, 'minute').fromNow();
    //il y a 2 m
    moment().subtract(1, 'year').fromNow();
    //il y a un an

 

Big thanks to Iskren for getting this in.

Save effort, save file size, be happy!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s