How to Speed Up AngularJS Apps That Use Internalization Libraries

by Ilya DrabeniaMay 22, 2014
Learn how to increase performance of AngularJS i18n internationalization up to 35x.

angularjs-logo

For a while, we were involved into development of a document workflow management-as-a-service system. The client app was created using AngularJS, and we were to decide on the best option for its internalization (i18n) and localization (l10n). However, the service had a rather complex UI with plenty of messages to be translated and transferred between the server and the client. Therefore, we were concerned about the impact of client-side translation on performance.

In this post, we explore this in detail and suggest an approach that accelerates performance of AngularJS internationalization.

 

Why AngularJS

After a brief investigation, we agreed that AngularJS would be a good match for this project for a number of reasons. First, development using this framework is quick, and the code quality is good. Second, delivered by Google, this tool is stable and reliable. In addition, it provides great testing capabilities. Another argument in favor of AngularJS is that it already provides features that should be added through third-party libraries in other solutions. For instance, to enable validation in Backbone.js, an additional jQuery validation plug-in is required; to provide a module structure, you will need RequireJS or any other library.

 

Internationalization with AngularJS

One of the simplest ways of translating AngularJS apps is to use internationalization libraries, such as Angular-translate, Angular-gettext, etc.

All these libraries use directives and filters to substitute values. However, this approach involves multiple modifications of the Document Object Model. In addition, large data sets are transferred between a server and a client. We analyzed how these two factors affected performance and measured the results using the R programming language.

This diagram illustrates how many milliseconds were added to a loading time depending on the number of words to be translated. For instance, translating 100 words at runtime results in a latency of 100+ milliseconds. If an application has a complex UI with multiple menus and tabs, then the number of translated messages may reach 300 and more.

According to surveys, users are ready to wait for 2 seconds, while a web page is loading and after 3 seconds 40% of visitors leave a website. An additional 100 milliseconds delay led to Amazon’s sales to decrease by 1%. Therefore, in case of AngularJS i18n and l10n, directives and filters should only be used for applications with few DOM elements.

We also analyzed how the size of a translated message bundle affects the entire page loading time. It turned out that loading 5–10 MB had a very low impact on performance.

 

Improving performance of AngularJS i18n

The latencies illustrated by the diagram above were primarily caused by modification of multiple DOM objects. So, reducing the number of such updates could help to improve performance.

To achieve this, the templates should be localized before they are converted into DOM elements. For example, the translated words can be added at the moment the templates are received by the server.

To analyze how this method of localization influences performance, we created a script that:

  • loaded message bundles to a client
  • used an AJAX interceptor to process loaded templates before they were converted to DOM elements
  • utilized the Underscore.js template to replace text in templates

The source code of this solution is as follows.

.factory('i18nInterceptor', ['$q', '$translate', function($q, $translate) {
            return {
                'request': function(config) {
                    return config;
                },

                'response': function(response) {
                    _.templateSettings = {
                        'interpolate': /\[\[([\s\S]+?)\]\]/g
                    };
                    if (typeof response.data === 'string') {
                        response.data = _.template(response.data, {t: $translate});
                    }
                    return response;
                }
            };
        }])

Here is a usage sample.

<div class=”box-header”>    
    <span class=”title”> [[t('common.tickets.page.search')]]: </span>
</div>

As you can see from the figure below, this approach works much faster. Translating 500 words resulted in a latency of less than 20 milliseconds, which is almost 35 times faster compared to the default Angular-gettext method.

The following diagram demonstrates the achieved performance improvement. The green line stands for the Angular-gettext library, the red line is based on optimized Angular-gettext solution that reduces the number of DOM modifications.

In this case, the optimized solution decreased the latency for translating 500 words by 35x: from 700 milliseconds to less than 20 milliseconds.

The project demonstrated how most of AngularJS libraries for internationalization and localization slow down the performance. While in a single-page app the latency may be slight, in large web systems this approach may increase loading time significantly. Therefore, it will only work for small-scale apps that do not have strict performance requirements.

To reduce the number of DOM modifications, maps with translations should be generated on the server side and the ready values should be inserted into templates on the client side. After all, a template with translated words should be converted to DOM elements. As it was demonstrated, this may improve performance by up to 35x.

 

Further reading


This post was written by Ilya Drabenia and edited by Alex Khizhniak.