Angular — ngx-translate

Use PolyCLI to automate translations in Angular projects that use @ngx-translate/core.

How it fits together

@ngx-translate/core is the most widely used i18n library for Angular. It loads plain JSON files at runtime — one file per language — and resolves translation keys in your templates and components. PolyCLI generates those JSON files automatically, so you only maintain the source language file and let the CLI handle everything else.

Folder structure

The conventional location for ngx-translate JSON files is src/assets/i18n/. PolyCLI will read your source file and write target files in the same folder.

text
src/assets/i18n/
├── en.json                  ← source file (you maintain this)
├── it.json                  ← generated by PolyCLI
├── es.json                  ← generated by PolyCLI
├── fr.json                  ← generated by PolyCLI
└── .translator-lock.json    ← delta tracking — commit this file

PolyCLI configuration

Run polycli init in your Angular project root and point localesPath at your i18n folder:

buildtranslator.json
{
  "sourceLanguage": "en",
  "targetLanguages": ["it", "es", "fr", "de"],
  "localesPath": "./src/assets/i18n"
}

Source file example

ngx-translate supports flat and nested JSON. Both work with PolyCLI. The default interpolation syntax uses {{ }} double braces — the same tokens PolyCLI protects automatically, so variable names are never sent to the translation API.

src/assets/i18n/en.json
{
  "app": {
    "title": "My Application",
    "loading": "Loading..."
  },
  "auth": {
    "welcome": "Welcome back, {{name}}!",
    "logout": "Log out"
  },
  "dashboard": {
    "items": "You have {{count}} items pending."
  }
}
src/assets/i18n/it.json (output)
{
  "app": {
    "title": "La Mia Applicazione",
    "loading": "Caricamento..."
  },
  "auth": {
    "welcome": "Bentornato, {{name}}!",
    "logout": "Esci"
  },
  "dashboard": {
    "items": "Hai {{count}} elementi in sospeso."
  }
}

The {{name}} and {{count}} tokens are restored verbatim and are not counted toward your credit usage.

Loading translations in Angular

Register TranslateModule with the HttpLoader pointing at your assets folder. The path matches exactly what PolyCLI writes.

app.config.ts
import { provideHttpClient } from '@angular/common/http'
import { TranslateModule, TranslateLoader } from '@ngx-translate/core'
import { TranslateHttpLoader } from '@ngx-translate/http-loader'
import { HttpClient } from '@angular/common/http'

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

export const appConfig = {
  providers: [
    provideHttpClient(),
    importProvidersFrom(
      TranslateModule.forRoot({
        loader: {
          provide: TranslateLoader,
          useFactory: createTranslateLoader,
          deps: [HttpClient],
        },
        defaultLanguage: 'en',
      })
    ),
  ],
}

Running in CI

Add the translation step before ng build in your pipeline so the generated JSON files are always up to date in the build output.

.github/workflows/build.yml (excerpt)
- name: Translate
  run: npx @polycli/cli run
  env:
    POLYCLI_API_KEY: ${{ secrets.POLYCLI_API_KEY }}

- name: Build Angular app
  run: ng build --configuration production
Commit src/assets/i18n/.translator-lock.json to version control alongside your generated language files. Without it, every CI run re-translates all strings from scratch.