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

In this tutorial, you’ll learn how to add full internationalization support to your Angular app using Transloco.

Step by step, we’ll guide you through installing and configuring the library, creating and managing translation files, and using translations directly in your components and templates.

You’ll discover how to handle dynamic parameters and formatted messages, switch between languages at runtime, and keep your translations consistent across the project.

Finally, we’ll show you how to make the process even smoother with BabelEdit, giving you powerful tools to edit and preview translations in multiple languages—all without leaving your development workflow.

Create a simple demo app (optional)

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.

  • Do you want to create a 'zoneless' application without zone.js (Developer Preview)? No
  • Which stylesheet format would you like to use? Sass (SCSS)
  • Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No

After a short time, the project is ready.

cd angular-transloco-example
npm run start

Open a browser and 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.

ng add @jsverse/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:

✔ 🌍 Which languages do you need? en, es
✔ 🚀 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.html and replace it with this content:

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

As already said at the start 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.

Update the src/app.ts to include the TranslocoDirective:

src/app.ts
import { Component } from '@angular/core';
import {TranslocoDirective} from "@jsverse/transloco";

@Component({
  selector: 'app-root',
  imports: [TranslocoDirective],
  templateUrl: './app.html',
  styleUrl: './app.scss'
})
export class App {
}

Also, update the angular.json file to include assets from the src/assets folder. By default, Angular now serves only the content of the public folder, so we need to explicitly configure it to serve our translation files.

angular.json
  "architect": {
        "build": {
          "builder": "@angular/build:application",
          "options": {
            "browser": "src/main.ts",
            "polyfills": [
              "zone.js"
            ],
            "tsConfig": "tsconfig.app.json",
            "inlineStyleLanguage": "scss",
            "assets": [
              {
                "glob": "**/*",
                "input": "public"
              },
              {
                "glob": "**/*",
                "input": "src/assets",
                "output": "assets"
              }
            ],
            "styles": [
              "src/styles.scss"
            ]
          },

Now run the app with

npm run start

you should see this:

Transloco tutorial app - no files loaded yet
The demo with no translation files loaded

Troubleshooting

The most likely error is that you see just a white screen. Open the console in the browser

Failed to load resource: the server responded with a status of 404 (Not Found)
hook.js:608 Error while trying to load "en" HttpErrorResponse
hook.js:608 ERROR Error: Unable to load translation and all the fallback languages

This means that the translation files are not loaded. Check your angular.json for the assets section and restart the server:

npm run start

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>

The second disadvantage of scopes is that BabelEdit will not ba able to find the translation IDs to display them in the source code preview.

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.

Editing Transloco JSON files in BabelEdit
Configuring your Transloco project in 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.

BabelEdit next asks for your source language — that is the language that you edit first and that is used for machine translation and other features.

Transloco - selecting the source language

Click on Configure... and select en-US.

Next, click Add ID or use one of these shortcuts to add a new translation ID:

  • Windows: CTRL+N
  • macOS: +N

You can now enter main.title and press OK... but it's easier with the automatic extraction tool inside BabelEdit to get the IDs from your source code.

Transloco - adding a new translation ID

Click on Extract from source code...

Transloco - extracting translation IDs with BabelEdit

... and next on Add all.

This method offers a quick and convenient way to add translation IDs from Transloco to BabelEdit. However, it's not perfect—it may miss some IDs in your source code. For example, if you're using Transloco’s scope feature, IDs inside your templates might not be detected. To ensure all translation IDs are extracted, use Transloco’s command-line tool instead. See the next section for details.

On the left side of BabelEdit, select the root node main in the left tree view to add them to the editor in the center view.

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.

Edit Transloco JSON translation file

Use BabelEdit's machine translation feature to translate the app

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

Transloco - using the machine translation with DeepL, OpenAI and Google 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.

BabelEdit's Export / Import feature is designed for working with translation agencies. You can export your translation files, send them for translation or review, and then re-import the updated files once the translations are complete.

... and in the app

Reload the app, and you should see this:

Transloco - the app with the English translations

Extract translations from source code and templates

As mentioned above, adding translations is easy with the built-in extractor — but it's not perfect when using advanced features in Transloco.

I highly recommend adding the extractor provided by Transloco and use it at least from time to time to update your files.

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 @jsverse/transloco-keys-manager to the project:

npm add -D @jsverse/transloco-keys-manager prettier

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

package.json
 ...
 "scripts": {
    "i18n:extract": "transloco-keys-manager extract --sort --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

The extractor has some options you might want to synchronize with BabelEdit to prevent heavy diffs in your files. In BabelEdit use Configuration from the toolbar:

transloco-keys-managerBabelEdit
--sortIf you don't sort, change Editor/Translation Order to Keep original order
--unflatFormat: JSON with namespaces

Switching Languages

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

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

Hint: The language names are not translated. This ensures that even if users can’t read the content, they can still recognize and select their language by its native name.

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 when done.

src/app.ts
import {Component, inject} from "@angular/core";
import {TranslocoDirective, TranslocoService} from "@jsverse/transloco";

@Component({
  selector: 'app-root',
  imports: [TranslocoDirective],
  templateUrl: './app.html',
  styleUrl: './app.scss'
})
export class App {
  translocoService = inject(TranslocoService);

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

Run the npm run i18n:extract or use the Add IDs in BabelEdit and enter these texts for the new IDs:

IDtext
locale-switch.labelChoose your language

So here's how the project looks now:

Transloco with language switcher

More ways to use translations in templates

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

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.html
<ng-container *transloco="let t">
 ...
    <h2>{{'pipe.title' | transloco}}</h2>
    <p>{{'pipe.greeting' | transloco: {name: 'Jill'} }}</p>
...
</ng-container>

Also add the TranslationPipe to the app.ts:

app.ts
import {Component, inject} from "@angular/core";
import {TranslocoDirective, TranslocoPipe, TranslocoService} from "@jsverse/transloco";

@Component({
  selector: 'app-root',
  imports: [TranslocoDirective, TranslocoPipe],
  templateUrl: './app.html',
  styleUrl: './app.scss'
})
...

Run the npm run i18n:extract or use the Add IDs in BabelEdit 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.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() {

    this.translocoService.selectTranslate('in-code.text', {count:5})
      .subscribe((text) => {
          console.log(text);
      });
  }
IDtext
in-code.textTranslation in code: This is mambo #{{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 all this 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 @jsverse/transloco-messageformat:

npm add @jsverse/transloco-messageformat

To activate the new feature, you have to add the provider to the src/app/app.config.ts.

src/app/app.config.ts
...
import {TranslocoHttpLoader} from "./transloco-loader";
import {provideTransloco} from "@jsverse/transloco";
import {provideTranslocoMessageformat} from "@jsverse/transloco-messageformat";

export const appConfig: ApplicationConfig = {
    providers: [
        ...
        provideTransloco({
            config: {
                availableLangs: ["en", "es"],
                defaultLang: "en",
                reRenderOnLangChange: true,
                prodMode: !isDevMode()
            },
            loader: TranslocoHttpLoader
        }),
        provideTranslocoMessageformat()
    ]
};

After restarting the app, nothing really changed.

Pluralization

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

<ng-container *transloco="let t">
    ...
    <h2>{{ t('message.title') }}</h2>

    <p>{{ t('message.pluralization', {count: 0}) }}</p>
    <p>{{ t('message.pluralization', {count: 1}) }}</p>
    <p>{{ t('message.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
message.pluralizationYou have {count, plural, =0 {no apples} one {one apple} other {# apples}}!
message.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. The other keyword serves as a fallback for any value that doesn't match the explicitly defined options.

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

Use it like this:

<ng-container *transloco="let t">
    ...
    <p>{{ t('message.select', {flavor: 'vanilla'}) }}</p>
    <p>{{ t('message.select', {flavor: 'strawberry'}) }}</p>
    <p>{{ t('message.select', {flavor: 'chocolate'}) }}</p>
</ng-container>
IDtext
message.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 languages right from the start.