The Angular 18 Archetype includes a complete internationalization (i18n) solution using @ngx-translate/core. The system supports multiple languages with automatic localStorage persistence and easy template integration.
Available languages
The application currently supports:
- English (en) - Default language
- Spanish (es)
Languages are defined in LanguageSwitchService.availableLanguages at src/app/core/language-switch/language-switch.service.ts:8
How it works
Translation files loaded
Translation JSON files are loaded from ./assets/i18n/ directory using TranslateHttpLoader.// src/app/config/httpLoaderFactory.ts
const httpLoaderFactory = (http: HttpClient) =>
new TranslateHttpLoader(http, './assets/i18n/', '.json');
Language initialized on app startup
The application uses APP_INITIALIZER to set up translations before the app starts:// src/app/config/httpLoaderFactory.ts
export function initializeTranslation(): () => void {
const translateService = inject(TranslateService);
const languageSwitchService = inject(LanguageSwitchService);
return () => {
translateService.addLangs(LanguageSwitchService.availableLanguages);
translateService.setDefaultLang(LanguageSwitchService.defaultLanguage);
languageSwitchService.initLanguageFromLocalStorage();
};
}
Language restored from localStorage
Previously selected language is automatically restored from localStorage:// src/app/core/language-switch/language-switch.service.ts
public initLanguageFromLocalStorage(): void {
const languageFromStorage = localStorage.getItem('language');
if (
languageFromStorage &&
LanguageSwitchService.availableLanguages.includes(languageFromStorage)
) {
this.setLanguage(languageFromStorage);
}
}
Language switching service
The LanguageSwitchService manages all language operations:
// src/app/core/language-switch/language-switch.service.ts
import { inject, Injectable } from "@angular/core";
import { TranslateService } from '@ngx-translate/core';
@Injectable({
providedIn: 'root',
})
export class LanguageSwitchService {
public static readonly availableLanguages: string[] = ['en', 'es'];
public static readonly defaultLanguage: string = LanguageSwitchService.availableLanguages[0];
private translateService: TranslateService = inject(TranslateService);
public setLanguage(languageId: string): void {
if (LanguageSwitchService.availableLanguages.includes(languageId)) {
this.translateService.use(languageId);
localStorage.setItem('language', languageId);
}
}
public getCurrentLanguage(): string {
if (
this.translateService.currentLang &&
this.translateService.currentLang !== LanguageSwitchService.defaultLanguage
) {
return this.translateService.currentLang;
}
return LanguageSwitchService.defaultLanguage;
}
}
Key methods
setLanguage(languageId: string) - Changes the active language and persists to localStorage
getCurrentLanguage() - Returns the currently active language
initLanguageFromLocalStorage() - Restores language preference on app initialization
Using translations in templates
The translate pipe makes it easy to display translated text in your templates:
<!-- Basic usage -->
<h1>{{ 'greeting' | translate }}</h1>
<!-- With parameters -->
<p>{{ 'welcome.message' | translate: { name: userName } }}</p>
Translation files
{
"greeting": "Hello World! :)"
}
Implementing a language switcher
Here’s a real example from the codebase showing how to create language switching buttons:
// src/app/core/language-switch/language-switch.component.ts
import { Component, inject } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { LanguageSwitchService } from './language-switch.service';
@Component({
standalone: true,
selector: 'app-navbar',
template: `
<button (click)="changeLang('en')">English</button>
<button (click)="changeLang('es')">Spanish</button>
`
})
export class NavbarComponent {
private languageSwitchService = inject(LanguageSwitchService);
constructor(private translate: TranslateService) {
translate.setDefaultLang('es');
}
changeLang(lang: string) {
this.languageSwitchService.setLanguage(lang);
}
}
Adding a new language
Create translation file
Add a new JSON file to src/assets/i18n/ (e.g., fr.json for French)
Update available languages
Add the language code to the availableLanguages array:// src/app/core/language-switch/language-switch.service.ts
public static readonly availableLanguages: string[] = ['en', 'es', 'fr'];
Add translation keys
Populate your new translation file with all required keys from the existing language files
Configuration
The translation system is configured in app.config.ts:
// src/app/app.config.ts
import { APP_INITIALIZER, ApplicationConfig, importProvidersFrom } from '@angular/core';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { initializeTranslation, provideTranslation } from './config/httpLoaderFactory';
export const appConfig: ApplicationConfig = {
providers: [
importProvidersFrom([TranslateModule.forRoot(provideTranslation())]),
{
provide: APP_INITIALIZER,
useFactory: initializeTranslation,
multi: true,
deps: [TranslateService],
},
]
};
Best practices
- Always use meaningful translation keys (e.g.,
user.profile.title instead of title1)
- Keep translation files synchronized across all languages
- Use the
translate pipe in templates instead of programmatic translation when possible
- Validate that all language codes exist before calling
setLanguage()