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-exampleThis 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 startOpen 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/translocoThe 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? NoUse 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:
<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.
tis memoized, so all translations are cached until they change- The
translocodirective 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:
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.
"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 startyou should see this:
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 startPassing 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.
<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.
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.

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.

Click on Extract from source code...

... 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:
| ID | text |
|---|---|
main.greeting | Hello {{name}}, see how easy it is to translate your Angular App! |
main.title | Angular + 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, simply 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.
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:

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 prettierTo make use of it, add the following lines to your 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:extractThe 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-manager | BabelEdit |
|---|---|
--sort | If you don't sort, change Editor/Translation Order to Keep original order |
--unflat | Format: JSON with namespaces |
Switching Languages
Reload the app — you should now see the English text. Let's add a language switch to support Spanish:
<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.
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:
| ID | text |
|---|---|
locale-switch.label | Choose your language |
So here's how the project looks now:
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:
<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:
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:
| ID | text |
|---|---|
pipe.greeting | Hello {{name}}, we are using pipes now! |
pipe.title | Translation Pipes |
Attribute directives
It's also possible to use the transloco="" attribute. To pass parameters,
you also need the [translocoParams]={...} attribute.
<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:
| ID | text |
|---|---|
attribute-directive.greeting | Hello {{name}}, this is an attribute directive! |
attribute-directive.title | Attribute 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.
constructor() {
this.translocoService.selectTranslate('in-code.text', {count:5})
.subscribe((text) => {
console.log(text);
});
}| ID | text |
|---|---|
in-code.text | Translation 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-messageformatTo activate the new feature, you have to add the provider to the 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".
| ID | text |
|---|---|
message.pluralization | You have {count, plural, =0 {no apples} one {one apple} other {# apples}}! |
message.title | ICU 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>| ID | text |
|---|---|
message.select | I 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:
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.