Skip to content
Angular i18n

Angular i18n Solution

Standalone components, signals, and SSR support for Angular applications.

Setup

Runtime translations in Angular, in three steps

Angular's built-in i18n compiles one bundle per locale. For translations that change without a rebuild, ngx-translate reads them from Better I18N at runtime.

Install the loader dependencies

ngx-translate provides the pipe, the service and the loader contract; core fetches and caches the messages.

terminalbash
npm install @ngx-translate/core @better-i18n/core

# @better-i18n/core ships zero dependencies —
# it is the same client our React SDKs are built on.

Write a TranslateLoader backed by the CDN

TranslateLoader asks for an Observable per language, so rxjs from() around getMessages is the whole adapter.

src/app/better-i18n.loader.tsts
import { Injectable } from '@angular/core'
import { TranslateLoader } from '@ngx-translate/core'
import { createI18nCore } from '@better-i18n/core'
import { from, Observable } from 'rxjs'

// Module scope: the 60s in-memory cache lives on the instance, so one
// client per app — not one per component.
const betterI18n = createI18nCore({
  projectId: 'your-org/your-project', // Settings → General → Project ID
  defaultLocale: 'en',
})

@Injectable({ providedIn: 'root' })
export class BetterI18nLoader implements TranslateLoader {
  // TranslateLoader's contract: one Observable of messages per language.
  getTranslation(lang: string): Observable<Record<string, unknown>> {
    return from(betterI18n.getMessages(lang))
  }
}

export { betterI18n }

Provide it and switch at runtime

One provider in bootstrapApplication, then use() changes language with no page reload and no per-locale build.

src/main.tsts
import { bootstrapApplication } from '@angular/platform-browser'
import { importProvidersFrom } from '@angular/core'
import { TranslateModule, TranslateLoader } from '@ngx-translate/core'
import { AppComponent } from './app/app.component'
import { BetterI18nLoader } from './app/better-i18n.loader'

bootstrapApplication(AppComponent, {
  providers: [
    importProvidersFrom(
      TranslateModule.forRoot({
        defaultLanguage: 'en',
        loader: { provide: TranslateLoader, useClass: BetterI18nLoader },
      })
    ),
  ],
})

How it works

Where an Angular string comes from

No per-locale bundle: the loader resolves a language at runtime and the edge answers it.

Read path — every locale load

Your Angular app

The translate pipe reads what TranslateService already loaded.

0 network calls per render

@better-i18n/core

getMessages(lang) inside the TranslateLoader — cached per language.

60s TTL · 0 deps

CDN edge

Cloudflare worker answers from the nearest edge cache.

max-age=60 · always 200

R2 object store

The published translation files the sync worker wrote.

source of truth

Fallback chain — tried in order when a hop fails

1In-memory TTL cache
2CDN fetch, with timeout and one retry
3Persistent storage, if configured
4staticData bundled with the app
5Throw — after everything above missed

Write path — dashboard to app

AI or translator

Proposal reviewed in the dashboard, glossary enforced.

MCP · dashboard · CLI

Publish

Sync worker writes the locale files to R2.

better-i18n publish

CDN purge

Fire-and-forget purge of the affected keys and the manifest.

non-critical by design

Live in the app

The next getMessages() past the TTL returns the new copy.

~60s worst case

0dependencies in core
60scache TTL, client and edge
200CDN status, even on failure
5fallback layers before an error
Switching locale

Quick Start

Add i18n to your Angular app with pipes and services.

src/app/locale-switcher.component.tsts
import { Component, inject } from '@angular/core'
import { TranslateModule, TranslateService } from '@ngx-translate/core'
import { betterI18n } from './better-i18n.loader'

@Component({
  selector: 'app-locale-switcher',
  standalone: true,
  imports: [TranslateModule],
  template: `
    <select (change)="switchTo($any($event.target).value)">
      <option *ngFor="let l of languages" [value]="l.code">{{ l.name }}</option>
    </select>
  `,
})
export class LocaleSwitcherComponent {
  private translate = inject(TranslateService)
  languages: { code: string; name: string }[] = []

  async ngOnInit() {
    // Locales come from the project manifest, not a hardcoded array.
    this.languages = await betterI18n.getLanguages()
  }

  switchTo(lang: string) {
    // use() calls the loader, which hits the cache or the CDN.
    this.translate.use(lang)
  }
}
In a template

In a template

The translate pipe and the service both read from the loader, so nothing in your components knows about the CDN.

src/app/app.component.htmlhtml
<!-- app.component.html -->
<h1>{{ 'home.title' | translate }}</h1>
<p>{{ 'home.greeting' | translate: { name: 'World' } }}</p>

<!-- ICU plurals authored in the Better i18n dashboard -->
<p>{{ 'cart.items' | translate: { count: 3 } }}</p>

<app-locale-switcher />
Capabilities

Features

Standalone components support
Signals support
Translation pipes
i18n directives
Injectable services
Lazy loading modules
Angular Universal SSR
AOT compilation support
Angular CLI integration
Works with

Works with Popular Angular i18n Libraries

Better I18N complements your Angular i18n library — manage translations visually, collaborate with translators, and deploy via CDN.

Better I18N + @ngx-translate/core

The most widely used Angular translation library. Runtime translations with pipes, directives, and service injection.Better I18N exports to ngx-translate JSON format. Edit translations in our dashboard, sync to your repo automatically.

Better I18N + Angular i18n (built-in)

Angular's official i18n system with AOT compilation, ICU expressions, and build-time translation extraction.Export to Angular XLIFF format. Better I18N manages the translation workflow, Angular CLI builds locale-specific bundles.

Better I18N + Transloco

Modern, lightweight i18n library for Angular with lazy loading, rich plugins, and excellent TypeScript support.Sync translations to Transloco JSON format via Better I18N's GitHub integration. Real-time updates with CDN delivery.

Explore Other Framework Guides

Get started

Start Building with Angular i18n

Free tier available. No credit card required.