Skip to main content

Angular Translation Setup

Introduction

Adding multi-language support to your Angular application makes it accessible to users from different regions and language backgrounds. This process, known as internationalization (i18n), allows your application to adapt to different languages without changing its core functionality.

In this tutorial, we'll learn how to set up translations in an Angular application using the popular @ngx-translate/core library. This library provides a simple way to manage translations and switch between languages dynamically.

Prerequisites

Before we start, make sure you have:

  • Basic knowledge of Angular
  • An existing Angular project or a new one created with Angular CLI
  • Node.js and npm installed

Installing @ngx-translate/core

Let's start by installing the required packages:

bash
npm install @ngx-translate/core @ngx-translate/http-loader --save

The @ngx-translate/core package contains the core functionality, while @ngx-translate/http-loader allows loading translation files using HTTP requests.

Setting Up the Translation Module

1. Create a Translation Files Structure

First, we'll create a folder structure for our translation files. In your Angular project, create the following structure:

src/
└── assets/
└── i18n/
├── en.json
├── es.json
└── fr.json

2. Add Translation Content

Let's add some basic translations to our JSON files:

en.json (English):

json
{
"HEADER": {
"TITLE": "My Application",
"HOME": "Home",
"ABOUT": "About",
"CONTACT": "Contact"
},
"WELCOME": {
"TITLE": "Welcome to My Application",
"MESSAGE": "This is an internationalized Angular application.",
"LANGUAGE_SELECT": "Select a language:"
},
"BUTTONS": {
"SUBMIT": "Submit",
"CANCEL": "Cancel"
}
}

es.json (Spanish):

json
{
"HEADER": {
"TITLE": "Mi Aplicación",
"HOME": "Inicio",
"ABOUT": "Acerca de",
"CONTACT": "Contacto"
},
"WELCOME": {
"TITLE": "Bienvenido a Mi Aplicación",
"MESSAGE": "Esta es una aplicación Angular internacionalizada.",
"LANGUAGE_SELECT": "Selecciona un idioma:"
},
"BUTTONS": {
"SUBMIT": "Enviar",
"CANCEL": "Cancelar"
}
}

fr.json (French):

json
{
"HEADER": {
"TITLE": "Mon Application",
"HOME": "Accueil",
"ABOUT": "À propos",
"CONTACT": "Contact"
},
"WELCOME": {
"TITLE": "Bienvenue sur Mon Application",
"MESSAGE": "C'est une application Angular internationalisée.",
"LANGUAGE_SELECT": "Sélectionnez une langue:"
},
"BUTTONS": {
"SUBMIT": "Soumettre",
"CANCEL": "Annuler"
}
}

3. Configure the Translation Module

Now, let's configure the translation module in our app. First, create a function to load the translation files:

typescript
// src/app/translation.loader.ts
import { HttpClient } from '@angular/common/http';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';

export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

Then, update your app.module.ts to include the TranslateModule:

typescript
// src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';

import { AppComponent } from './app.component';
import { createTranslateLoader } from './translation.loader';

@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule,
TranslateModule.forRoot({
defaultLanguage: 'en',
loader: {
provide: TranslateLoader,
useFactory: createTranslateLoader,
deps: [HttpClient]
}
})
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

Using Translations in Components

1. Setting Up the Root Component

First, let's update our app.component.ts to initialize the translate service:

typescript
// src/app/app.component.ts
import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
availableLanguages = [
{ code: 'en', name: 'English' },
{ code: 'es', name: 'Español' },
{ code: 'fr', name: 'Français' }
];

currentLang: string;

constructor(private translate: TranslateService) {
// Get browser language or default to English
const browserLang = translate.getBrowserLang();
this.currentLang = browserLang.match(/en|es|fr/) ? browserLang : 'en';

// Set default language
translate.setDefaultLang('en');

// Use current language
translate.use(this.currentLang);
}

changeLanguage(langCode: string): void {
this.translate.use(langCode);
this.currentLang = langCode;
}
}

2. Update the Template

Now, let's update the app.component.html to use our translations:

html
<!-- src/app/app.component.html -->
<header>
<h1>{{ 'HEADER.TITLE' | translate }}</h1>
<nav>
<ul>
<li><a href="#">{{ 'HEADER.HOME' | translate }}</a></li>
<li><a href="#">{{ 'HEADER.ABOUT' | translate }}</a></li>
<li><a href="#">{{ 'HEADER.CONTACT' | translate }}</a></li>
</ul>
</nav>
</header>

<main>
<div class="welcome-section">
<h2>{{ 'WELCOME.TITLE' | translate }}</h2>
<p>{{ 'WELCOME.MESSAGE' | translate }}</p>

<div class="language-selector">
<label>{{ 'WELCOME.LANGUAGE_SELECT' | translate }}</label>
<select [(ngModel)]="currentLang" (change)="changeLanguage(currentLang)">
<option *ngFor="let lang of availableLanguages" [value]="lang.code">
{{ lang.name }}
</option>
</select>
</div>
</div>

<div class="action-buttons">
<button>{{ 'BUTTONS.SUBMIT' | translate }}</button>
<button>{{ 'BUTTONS.CANCEL' | translate }}</button>
</div>
</main>

Don't forget to add the FormsModule to your app.module.ts for the select element to work:

typescript
import { FormsModule } from '@angular/forms';

@NgModule({
// ...
imports: [
BrowserModule,
HttpClientModule,
FormsModule,
TranslateModule.forRoot({
// ...
})
],
// ...
})

Advanced Translation Techniques

1. Using Translation Parameters

The @ngx-translate/core library allows you to pass parameters to your translations. Let's update our translation files to include parameters:

en.json (add this):

json
{
"GREETINGS": {
"HELLO": "Hello, {{name}}!",
"ITEMS_COUNT": "You have {{count}} items in your cart."
}
}

Similar updates should be made to the other language files.

In your component, you can pass parameters like this:

typescript
import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
selector: 'app-greeting',
template: `
<div>
<p>{{ 'GREETINGS.HELLO' | translate:{ name: userName } }}</p>
<p>{{ 'GREETINGS.ITEMS_COUNT' | translate:{ count: itemsCount } }}</p>
</div>
`
})
export class GreetingComponent {
userName = 'John';
itemsCount = 5;

constructor(private translate: TranslateService) {}
}

2. Programmatic Translation

Sometimes you need to translate strings programmatically, not just in the template. Here's how:

typescript
import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
selector: 'app-programmatic-example',
template: `
<div>
<p>{{ translatedText }}</p>
<p>{{ translatedGreeting }}</p>
</div>
`
})
export class ProgrammaticExampleComponent implements OnInit {
translatedText: string;
translatedGreeting: string;

constructor(private translate: TranslateService) {}

ngOnInit() {
// Get a simple translation
this.translate.get('WELCOME.TITLE').subscribe((res: string) => {
this.translatedText = res;
});

// Get a translation with parameters
this.translate.get('GREETINGS.HELLO', { name: 'Sarah' }).subscribe((res: string) => {
this.translatedGreeting = res;
});
}
}

3. Translation in Services

You can also use translations in your services:

typescript
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Injectable({
providedIn: 'root'
})
export class NotificationService {
constructor(private translate: TranslateService) {}

showSuccessMessage(userName: string): string {
let message = '';

this.translate.get('NOTIFICATIONS.SUCCESS', { name: userName })
.subscribe((res: string) => {
message = res;
});

return message;
}
}

Real-World Example: Multi-Language Form

Let's create a practical example of a contact form with multi-language support:

First, add the necessary translations to our JSON files:

en.json (add this):

json
{
"CONTACT_FORM": {
"TITLE": "Contact Us",
"NAME_LABEL": "Full Name",
"EMAIL_LABEL": "Email Address",
"MESSAGE_LABEL": "Your Message",
"SUBMIT_BUTTON": "Send Message",
"SUCCESS_MESSAGE": "Your message has been sent successfully!",
"ERROR_MESSAGE": "There was an error sending your message. Please try again.",
"NAME_REQUIRED": "Name is required",
"EMAIL_REQUIRED": "Email is required",
"EMAIL_INVALID": "Please enter a valid email address",
"MESSAGE_REQUIRED": "Message is required"
}
}

Now, let's create a contact form component:

typescript
// src/app/contact-form/contact-form.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';

@Component({
selector: 'app-contact-form',
templateUrl: './contact-form.component.html',
styleUrls: ['./contact-form.component.css']
})
export class ContactFormComponent {
contactForm: FormGroup;
formSubmitted = false;
formSuccess = false;
formError = false;

constructor(
private fb: FormBuilder,
private translate: TranslateService
) {
this.createForm();
}

createForm() {
this.contactForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
message: ['', Validators.required]
});
}

onSubmit() {
this.formSubmitted = true;

if (this.contactForm.valid) {
// Simulate form submission
setTimeout(() => {
this.formSuccess = true;
this.formError = false;
this.contactForm.reset();
this.formSubmitted = false;
}, 1000);
}
}

getErrorMessage(controlName: string): string {
const control = this.contactForm.get(controlName);

if (control.hasError('required')) {
return `CONTACT_FORM.${controlName.toUpperCase()}_REQUIRED`;
}

if (controlName === 'email' && control.hasError('email')) {
return 'CONTACT_FORM.EMAIL_INVALID';
}

return '';
}
}

The HTML template would look like:

html
<!-- src/app/contact-form/contact-form.component.html -->
<div class="contact-form-container">
<h2>{{ 'CONTACT_FORM.TITLE' | translate }}</h2>

<div *ngIf="formSuccess" class="success-message">
{{ 'CONTACT_FORM.SUCCESS_MESSAGE' | translate }}
</div>

<div *ngIf="formError" class="error-message">
{{ 'CONTACT_FORM.ERROR_MESSAGE' | translate }}
</div>

<form [formGroup]="contactForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="name">{{ 'CONTACT_FORM.NAME_LABEL' | translate }}</label>
<input type="text" id="name" formControlName="name">
<div *ngIf="formSubmitted && contactForm.get('name').invalid" class="validation-error">
{{ getErrorMessage('name') | translate }}
</div>
</div>

<div class="form-group">
<label for="email">{{ 'CONTACT_FORM.EMAIL_LABEL' | translate }}</label>
<input type="email" id="email" formControlName="email">
<div *ngIf="formSubmitted && contactForm.get('email').invalid" class="validation-error">
{{ getErrorMessage('email') | translate }}
</div>
</div>

<div class="form-group">
<label for="message">{{ 'CONTACT_FORM.MESSAGE_LABEL' | translate }}</label>
<textarea id="message" formControlName="message" rows="5"></textarea>
<div *ngIf="formSubmitted && contactForm.get('message').invalid" class="validation-error">
{{ getErrorMessage('message') | translate }}
</div>
</div>

<button type="submit" class="submit-button">
{{ 'CONTACT_FORM.SUBMIT_BUTTON' | translate }}
</button>
</form>
</div>

Don't forget to add ReactiveFormsModule to your app.module.ts:

typescript
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
// ...
imports: [
// ...
ReactiveFormsModule
],
// ...
})

Persisting Language Preferences

A good user experience includes remembering the user's language preference. Let's add that functionality:

typescript
// src/app/app.component.ts
import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
availableLanguages = [
{ code: 'en', name: 'English' },
{ code: 'es', name: 'Español' },
{ code: 'fr', name: 'Français' }
];

currentLang: string;

constructor(private translate: TranslateService) {
// Check for saved language preference
const savedLang = localStorage.getItem('preferred-lang');

// If no saved preference, get browser language or default to English
if (!savedLang) {
const browserLang = translate.getBrowserLang();
this.currentLang = browserLang.match(/en|es|fr/) ? browserLang : 'en';
} else {
this.currentLang = savedLang;
}

// Set default language
translate.setDefaultLang('en');

// Use current language
translate.use(this.currentLang);
}

changeLanguage(langCode: string): void {
this.translate.use(langCode);
this.currentLang = langCode;

// Save language preference
localStorage.setItem('preferred-lang', langCode);
}
}

Summary

In this tutorial, we've covered:

  1. Setting up @ngx-translate/core in an Angular application
  2. Creating and organizing translation files
  3. Using the translate pipe in templates
  4. Passing parameters to translations
  5. Using translations programmatically
  6. Creating a real-world example with a multi-language form
  7. Persisting user language preferences

With this setup, your Angular application can now support multiple languages, providing a better experience for international users. As your application grows, you can easily add more languages and translation keys to support your expanding user base.

Additional Resources

Exercises

  1. Add a new language to the application (e.g., German or Japanese)
  2. Create a language switcher component that shows flags for each available language
  3. Implement a "translator mode" that shows the translation key alongside the translated text (useful for debugging)
  4. Create a service to automatically detect and set the user's language based on their browser settings
  5. Implement lazy loading of translation files to improve initial load performance


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)