When you decide to use Angular in a project, it means that you are building a large SPA (otherwise, you should think of another framework). Large projects are usually intended for users in different countries and are carried out with translations of the application.
The library that, in my opinion,is the best to implement translation in an application belonging to Angular’s ecosystem is @ngx-translate. I have used this library since the beginning of the same because it is simple, powerful and very useful.
However, the biggest drawback that I find this library is that the translations are based on a key-value translation object in which to identify the key that you want to translate you must specify a string. The fact of using a string causes us to lose all the type control of the variables that we want to translate.
We can not know if a key is lost, incomplete or has typo.
We do not have autocomplete, despite having nested objects that can be complex.
You can not change the name of a key automatically (refactoring) between all the languages, we must modify each file of languages one by one.
In this post we will build a small service that will allow us to considerably improve the use of @ngx-translate in our software development.
Before starting, you can see the final result of what we are going to build in the next gif:
First, you will configure @ngx-translate in a conventional way, as recommended by the author on the GitHub page.
First you need to install the npm module:
You have to import TranslateModule.forRoot() in the root NgModule of your application.
The forRoot static method is a convention that provides and configures services at the same time. Make sure you only call this method in the root module of your application, most of the time called AppModule. This method allows you to configure the TranslateModule by specifying a loader, a parser and/or a missing translations handler.
By default, there is no loader available. You can write your own loader, or import an existing one. For example you can use the TranslateHttpLoader that will load translations from files using HttpClient.
To use it, you need to install the http-loader package from @ngx-translate:
Once you’ve imported the TranslateModule, you can put your translations in a json file that will be imported with the TranslateHttpLoader. The following translations should be stored in eng.json and span.json.
You can either use the TranslateService, the TranslatePipe or the TranslateDirective to get your translation values.
In your component, define param like this:
The first thing we need to do is create a new service named translations which will resolve the path of where the translation key is being specified is located.
Of course, the code can be refactored later but the objective of this post is to illustrate how @ngx-translate can be typed.
First of all, the GenericClass function has been defined, which is used to provide properties to any class that extends from it:
The second step is to create the service extending from GenericClass in which you specify that the properties belonging to the eng.ts file will be the properties of the Translations class.
The next step is to build the transformObjectToPath function, which is responsible for building an object with the keys' path of the .ts files, where the value would be the complete path so that @ngx-translate receives the string it expects.
At the end of executing this method, the class will have the following compound object inside:
Finally, the code associated with the service is the following one:
The files with the translations are .TS files instead of .json files, so they are as follows:
Another modification that must be made in the code is to define our own loader for @ngx-translate, since the .json files are not going to be downloaded using the httpClient service but rather a charger, that will be created to allow perform the loading of TS files as shown below:
The loader has been called WebpackTranslateLoader because Webpack is the one in charge of analyzing the possible files that are imported with the keyword import (...) and packages them as independent sources in order to carry out their request dynamically. Therefore, at the moment the file is requested, the request is made to the file /assets/i18n/language.js.
The last and most pleasant step is the use of @ngx-translate with typing in the component that you want to inject multi-language texts. It is necessary to inject the translations service, which must be public to be able to interact with the template.
Finally, magic can be seen in what is available:
- Detection of lost keys.
Another interesting point that can be the icing on the cake is to be able to refactor all the language files easily.
In this case, we can apply two techniques:
- Strong Typing. Warn if a key is not in the language file.
2. Typing. A casting that gives you typing, but does not warn you if a key is missing
The incredible final result is the one shown in the following GIF.
The GitHub branch of this post is https://github.com/Caballerog/angular-ngx-translate-typing
Originally published at https://carloscaballero.io/angular-ngx-translate-typings