Internationalization in Angular 10
Internationalization in Angular 10

The problem of internationalizing applications has been around for as long as software development has existed. Today I would like to discuss the workflow I use to solve this problem in Angular projects 🗺️. It should be noted that there are a plethora of ways handling some of these issues and this is an opinionated presentation of how I do it.

To get started let’s discuss what internationalization really means. Sure, it is about translating your application into a different language, sounds simple enough. However there is way more to it than translating texts.

Pluralization

Different languages might handle plural terms words in different ways. Image that your application displays the last time you have logged in. You may need to show different texts depending on how long ago that was, for example: (1) You logged in just now, (2) You logged in a minute ago, (3) You logged in few minutes ago or (4) You logged in 25 minutes ago. In a case like this we needed four different versions of this label in English. However, you might need less or more sentences to translate this into a different language.

Sentence Structure

Different languages have different grammar rules and sentence structures. In English you might say “Steve liked this picture” where the subject of the sentence [Steve] is the very first word. However, in another language, like Spanish, you might write it in a different order “A Steve le gustó esta foto”.

Date Format

This one is a little more obvious and in general easier to handle. Different countries handle date formats in different ways. For example, in the US the standard format is month/day/year while in Brazil (and many other countries) the used format is day/month/year. There is also the names of weekday and months.

Decimal and Thousands Separators

Different countries might use different symbols for decimal and thousands separators. For example, in the US one might write a number like this: 1,000.45, whereas in Brazil we would write that same value like so: 1.000,45. Additionally, currencies are handled in a similar way.

Angular Ecosystem

When it comes to internationalization of Angular apps there are a series of options, some more robust and some easier to configure than others. I will discuss the pros and cos of two commonly used options: the included i18n module and the third party library ngx-translate.

Angular comes with an i18n module out of the box. It handles a lot of the more difficult issues such as pluralization and alternate translations. Also, it is very stable and fully integrated with the Angular CLI. However, it has two major flaws. The first one being that you must deploy a different version of your application for each language you want to use. As a consequence the user can’t change the language dynamically from the browser. The other issue has to do with tooling provided to create the translation files. They are very simple and that can impact productivity in large projects.

One alternative is a popular library called ngx-translate. It targets the biggest issue of the built-in tool: dynamic translation. This means that you can switch between as many languages as you like in runtime. Additionally, you only need to build and deploy a single version of the application. However, the translation mechanism is simpler and does not provide some of the more robust features such as pluralization and alternate translations.

In small and simple projects I’d go with ngx-translate since it is very easy to use and configure. However, for large projects I prefer using the i18n module with some additional tooling to counterbalance some of its weaknesses that I will mention below. The biggest reason for this is that I believe that the set of features provided by the Angular module are more appropriate for a large project. Additionally, I believe that over time the Angular team will evolve the i18n module to the point where these third party libraries will become obsolete.

The i18n Module

Now let’s look at how to translate your Angular application!

First of all, the most common translation cases can be solved easily by angular pipes. The DatePipe will format a date value according to locale rules. You can also use the CurrencyPipe and DecimalPipe to deal with currencies and numbers in general. These pipes use the LOCALE_ID token to know how to format their output.

Marking the files for translation

The first step in the translation is to tag every element in the application that needs translations, by adding a property to the html tag that contains the text to be translated like so:

In case you to like to translate a piece of text without generating a tag you can do it like so:

To translate html attributes you add a property in the format i18n-{attribute name}. For example, to translate the title attribute of an image tag you would mark it like so:

You may also mark tags that include interpolated values like so:

You can find more examples and detailed explanations for how to handle more advanced cases such as pluralization and alternate texts on their website.

Generating translation files

Once all the proper html files have been tagged the next step is to generate the translation file. This process is automated and produces a single file which we’ll then use to translate the application. These files can be generated in a few different formats but we’ll use the default of xlf. To generate this file run the command below. Optionally you may specify the folder and name of the generated file. By default the file will be placed at src/messages.xlf.

Translating the file

The next step is to create a copy of this file for each language you like to translate to. For example we could name a copy of the file messages.es.xlf for Spanish translation. Now, we’ll open the file for each language and perform the translations. The generated files are essentially a series of translation units, like so:

To translate the file, you must translate each of these blocks. To translate this unit duplicate the block <source>...</source> and rename it <target>...</target>. Then replace the contents of this block with the translated text, like so:

Translating plural and alternate expressions works in a similar way. Here is an example of a plural block before and after the translation:

More details of how to translate to plural, alternate and nested expressions can be found here.

Building

Before building the app we need to make some adjustments to the angular.json configuration file. Add a property called i18n and configure it like indicated below. Note that the key of the object is the locale and the value is the path to translation file. Remember to replace fr with the unicode locale identifier you are going to translate into.

You are ready to build your application:

Angular will build a set of artifacts for each locale you have configured. For example, if you configure translations for French and Spanish it will build a version for those languages as well as a version in English. You are set!

Further improving the workflow

This is a simplified version of the workflow. There are a few issues with working this way that you might have noticed. Let’s say for example that you extracted the terms and translated the entire application. However, a few weeks later you added a new feature to the application that has a few labels that need translation. Now you have to extract the translation file again and translate it from scratch or you have to manually merge your already translated file with the new labels that you just added. This is time consuming and error prone. Especially if we are talking about a large project that involves multiple developers and where features are added everyday. In essence this approach becomes unusable.

To deal with this sort of problem there is a third party tool that automates this merge process and make this workflow viable: ngx-18n-support.


And that concludes the end of this post! I hope you found this to be useful 😎. In case you would like to get in touch: linkedin.