How to translate your Angular app with Transloco

Andreas Löw
Last updated:
GitHub
How to translate your Angular app with Transloco

What you are going to learn

Is this tutorial, you are going to learn how to …

Create a simple demo app

This step is optional — if you already have an application you want to localize, feel free to skip this section.

Start by creating an empty project. I prefer not to install the ng command locally, so I use npx to create a new project:

npx -p @angular/cli ng new angular-transloco-example

This command asks you some questions. We don't need a router for this and we don't use stylesheets either.

Would you like to add Angular routing? (y/N) -> N
Which stylesheet format would you like to use? -> SCSS

After a short time, the project is ready.

cd angular-transloco-example
npm run ng serve

Open a browser an navigate to http://localhost:4200/ — you should see the default Angular page of your app.

Add Transloco to your application

Let's now add Transloco to the application.

npm run ng add @ngneat/transloco

The installer again asks you some questions. The installer automatically enables Transloco in your application. If you are using your own project, make sure that you've committed all changes to your version management system so that you have a backup in case something goes wrong!

Answer the questions as follows:

The package @ngneat/transloco@6.0.0 will be installed and executed.
Would you like to proceed? Yes.   --> Yes
✔ Packages successfully installed.
? 🌍 Which languages do you need? (en, es).   --> ok for the demo, choose what you want
? 🚀 Are you working with server side rendering?     --> No

Use translations in your templates

With Transloco, you have several options to translate your templates. I'll show you all of them. Let's begin with the most efficient way, the structural directive.

Structural Directive

Clear src/app.component.html and replace it with this content:

src/app.component.html
<ng-container *transloco="let t">
  <h1>{{ t('main.title') }}</h1>
  <p>{{ t('main.greeting', { name: 'John' }) }}</p>
</ng-container>

As already said at the beginnin of this chapter, this is the most efficient way to use translations in your template.

  • t is memoized, so all translations are cached until they change
  • The transloco directive listens to language changes and refreshes the app. With several translations on a page, only a single observer is installed.

Passing values to components

You can also use the t() function to pass translations to other components. This is just an example - don't add it to your project since there is no <heading-component/>:

<heading-component [title]="t('dialog.title')"></heading-component>

Scopes

You can also save some typing by passing read:'scope-name' to the transloco directive. This saves a bit of typing in your template because with the scope main you can now type t('title') instead of t('main.title').

I recommend not to use scopes. If you use your editor to search for main.title, you can easily find it. If you set the scope to main and you just write title in the component, you'll find all titles in all files.

You can add the following block to the app.component.html template. It'll give you the same output as the one from above.

src/app.component.html
<ng-container *transloco="let t; read: 'main'">
    <h1>{{ t('title') }}</h1>
    <p>{{ t('greeting', { name: 'John' }) }}</p>
</ng-container>

Extract translations from source code and templates

As developers, we are as efficient as possible. So the least thing I would want to do is to manually add new translation IDs to my files. Let's add @ngneat/transloco-keys-manager to the project:

npm add -D @ngneat/transloco-keys-manager

To make use of it, add the following lines to your package.json:

package.json
 ...
 "scripts": {
    "i18n:extract": "transloco-keys-manager extract --default-value ''",
    "i18n:find": "transloco-keys-manager find",
    ...
  },

Run the following command to update the translation files with the new IDs:

npm run i18n:extract

Editing translation files the easy way

I know you are a developer, and you know how to edit JSON files. Believe me; I've been there, too. The project starts with some translations, but the longer you work on the project, the messier it gets. Keeping all the translation files in sync is not an easy job. And how could you preview your app in different languages?

This is why we've developed BabelEdit: The translation file editor for developers! Download it here and install it on your computer. It runs on Windows, macOS and Linux!

Configuring your project in BabelEdit

When done, drop the root folder of your application onto BabelEdit.

BabelEdit asks you to confirm the language files it found in your project.

  • ../src/assets/i18n/en.json: en-US
  • ../src/assets/i18n/es.json: es-ES

That's perfect! Click Ok.

Select the root node main in the left tree view to select the items for editing in the center view.

At the bottom of the center view, you should see a yellow box that ask you to select your primary language. Click Configure.. and select en-US. Close the dialogs.

How a 2nd yellow box pops up and asks, if you want to enable machine translation. Click on Enable.

In the center view, enter the following text in the en-US field:

IDtext
main.greetingHello {{name}}, see how easy it is to translate your Angular App!
main.titleAngular + Transloco Example

{{name}} is a placeholder for the name parameter we provided in the template.

Use BabelEdit's machine translation feature to translate the app

To also add the Spanish translations, just click the Pre-Translate button in the toolbar. Select DeepL and click Translate.

Saving

BabelEdit directly works on your JSON translation files. However, it also requires an additional project file to store your configuration and some meta data. When clicking on Save in the toolbar, it asks you for that file first. Name the file translations.babel and save it in your project root. Also make sure to check it into your version management system so that others can use the same configuration on their computer.

Switching Languages

Reload the app — you should now see the English text. Let's add a language switch to support Spanish:

src/app.component.html
<ng-container *transloco="let t">
    <div style="display:flex; gap:1rem">
        <span>Select your language:</span>
        <button (click)="switchLanguage('en')">English</button>
        <button (click)="switchLanguage('es')">Español</button>
    </div>
</ng-container>

Implement the new switchLanguage() method in the component. It requires access to the TranslocoService which you can get using dependency injection in the constructor.

So switch the language, all you have to do is to use call setActiveLang() with the language code.

Transloco loads the new language file in the background and refreshes the UI then done.

src/app.component.ts
import { Component } from '@angular/core';
import {TranslocoService} from "@ngneat/transloco";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  constructor(private translocoService: TranslocoService) {
  }

  switchLanguage(lang:string) {
    this.translocoService.setActiveLang(lang);
  }
}

More ways to use translations in templates

There are some more options to use translations in the tempaltes.

When using multiple translations, you should use the structural directive you already used. I am just showing you these methods so that you know, they exist.

Pipes

To use the pipes, you have to write the id, followed by a | transloco. You can also pass an object with the parameters for the translation:

src/app.component.html
<h2>{{'pipe.title' | transloco}}</h2>
<p>{{'pipe.greeting' | transloco: {name: 'Jill'} }}</p>

Run the npm run i18n:extract and enter these texts for the new IDs:

IDtext
pipe.greetingHello {{name}}, we are using pipes now!
pipe.titleTranslation Pipes

Attribute directives

It's also possible to use the transloco="" attribute. To pass parameters, you also need the [translocoParams]={...} attribute.

src/app.component.html
<h2 transloco="attribute-directive.title"></h2>
<p transloco="attribute-directive.greeting" [translocoParams]="{ name: 'Ben' }"></p>

Run the npm run i18n:extract and enter these texts for the new IDs:

IDtext
attribute-directive.greetingHello {{name}}, this is an attribute directive!
attribute-directive.titleAttribute directives

Using translations in code

It's — of course — also possible to use translations inside code.

It's not complicated, but there are some things you should be aware of:

  • the code might get executed before the language file list loaded
  • the language file might change after the initial run

This is why you should use obervers to get the translations.

src/app.component.ts
  constructor(private translocoService: TranslocoService) {

    this.translocoService.selectTranslate('in-code.text', {count:5})
      .subscribe((text) => {
          console.log(text);
      });
  }
IDtext
in-code.textThis text is translated in code. The function is called each time, the language changes. Value={{count}}

Open the browser console. You should see the console output each time you switch the languages.

Formatting messages with ICU message syntax

There are many cases in which your text changes depending on a parameter. You could handle this all in code, using different translation strings for the values.

  • 0: You have no apples!
  • 1: You have one apple!
  • >=2: You have {{value}} apples!

This makes the code and templates more complex and not very readable. Adding more parameters makes it even more complex.

Installing Transloco MessageFormat

Transloco handles all this with the so-called ICU message format. For this, let's install @ngneat/transloco-messageformat:

npm add @ngneat/transloco-messageformat

To activate the new feature, you have to add the provider to the transloco-root.module.ts.

src/transloco-root.module.ts
...
import { TranslocoHttpLoader } from './transloco-loader';
import { provideTranslocoMessageformat } from '@ngneat/transloco-messageformat';

@NgModule({
    providers: [
        provideTransloco({
            ...
        }),
        provideTranslocoMessageformat()   // After provideTransloco()
    ]
    ...
})
export class TranslocoRootModule {}

After restarting the app, nothing really changed.

Pluralization

Pluralization means changing the text depending on a count. Add the following code to your template:

<!-- translations with ICU syntax: pluralization -->
<ng-container *transloco="let t">
  <h2>{{ t('icu.title') }}</h2>

  <p>{{ t('icu.pluralization', {count: 0}) }}</p>
  <p>{{ t('icu.pluralization', {count: 1}) }}</p>
  <p>{{ t('icu.pluralization', {count: 10}) }}</p>
</ng-container>

There's nothing special about that. The magic happens inside the messages:

{count, plural, =0 {no apples} one {one apple} other {# apples}}

This switches on a parameter named count. It uses pluralization — keyword: plural. If count=0, it uses the text "no apples". If count=1 it writes "one apple" and in all other cases the amount followed by "apples".

IDtext
icu.pluralizationYou have {count, plural, =0 {no apples} one {one apple} other {# apples}}!
icu.titleICU Message Formatting

Selections

Use selections if you want to convert strings (e.g. definitions in your code) to localized display strings.

E.g. if you use different ice cream flavors. Internally, you use vanilla and strawberry, but you want to display the names.

This is similar to what we did before. It switches on the parameter flavor using the select format. After that, the list contains names followed by their translations. other is the fallback for an unknown value.

I like {flavor, select, vanilla {vanilla}  strawberry {strawberry} other {all}} ice cream.

Use it like this:

  <p>{{ t('icu.select', {flavor: 'vanilla'}) }}</p>
  <p>{{ t('icu.select', {flavor: 'strawberry'}) }}</p>
  <p>{{ t('icu.select', {flavor: 'chocolate'}) }}</p>
IDtext
icu.selectI like {flavor, select, vanilla {vanilla} strawberry {strawberry} other {all flavors of}} ice cream.

Translating ICU syntax in BabelEdit

DeepL, Google Translate and Bing all do not correctly translate ICU message syntax. If you translate the message to Spanish, you see that the parts in the brackets are not translated.

To fix this, use the Consistency AI feature of BabelEdit. It checks translations for consistency with your primary language and reports differences.

Select the icu tree leaf in the left panel and run the Consistency AI. You should see something like this in the output:

Your project
Proposed change
en-US:
You have {count, plural, =0 {no apples} one {one apple} other {# apples}}!
The translation for 'apples' was not translated to Spanish.
es-ES:
¡Tienes {count, plural, =0 {no apples} one {one apple} other {# apples}}!
¡Tienes {count, plural, =0 {no manzanas} one {una manzana} other {# manzanas}}!

Click the to accept the change. The translation is better now — but it's still not perfect. After all, this is a tool to help you preview your application and possibly speed up the translation process. It's not meant to completely replace a human translator.

Conclusion

Translating your Angular App with Transloco is easy. You should start using it early during development. If you also use BabelEdit, you can preview your application in multiple langugages right from the start.