NgxSignalTranslate
May 12, 2026 ยท View on GitHub
Signal-first i18n for Angular: lazy-loaded JSON resources, and a service with sync, signal, and observable APIs.
Highlights
- Lazy-load language JSON over HTTP; each language loads once and caches.
- Service APIs:
translate(sync, signal-friendly),translate$(observable that waits for language load), andsetLanguage. - Placeholder replacement with
string | numberparams.
Install
npm install ngx-signal-translate
Configure
Register the config provider in app.config.ts (or your bootstrap providers). The path is optional; default is the app root.
import { ApplicationConfig } from '@angular/core';
import { provideSignalTranslateConfig } from 'ngx-signal-translate';
export const appConfig: ApplicationConfig = {
providers: [provideSignalTranslateConfig({ path: 'assets/i18n' })],
};
Set the initial language (for example in your root component):
import { Component, inject } from '@angular/core';
import { NgxSignalTranslateService } from 'ngx-signal-translate';
@Component({
selector: 'app-root',
template: '<router-outlet />',
})
export class AppComponent {
readonly #translate = inject(NgxSignalTranslateService);
constructor() {
this.#translate.setLanguage('en');
}
}
Language files
- Files are JSON, named by language code (e.g.,
en.json,de.json). - Keys map to strings; unknown keys return the key name.
Example en.json:
{
"HELLO": "Hello",
"HELLO_NAME": "Hello {name}"
}
Placeholders use {key} syntax and are replaced with TranslateParams values (string or number).
Usage
Templates (recommended)
Since Angular tracks signal reads inside template expressions, you can call translate() directly โ it's already reactive. This avoids creating pipe-level signal wrappers and is the recommended default for normal template usage.
import { Component, inject } from '@angular/core';
import { NgxSignalTranslateService } from 'ngx-signal-translate';
@Component({
selector: 'demo-cmp',
standalone: true,
template: `
<p>{{ ngxSignalTranslate.translate('HELLO') }}</p>
<p>{{ ngxSignalTranslate.translate('HELLO_NAME', { name: 'Ada' }) }}</p>
<input [placeholder]="ngxSignalTranslate.translate('Search')" />
<button [attr.aria-label]="ngxSignalTranslate.translate('Save')">๐พ</button>
`,
})
export class DemoComponent {
protected readonly ngxSignalTranslate = inject(NgxSignalTranslateService);
}
For high-frequency rendering, such as large lists or translations with inline params, prefer moving repeated translations into a computed() value. This avoids rebuilding params and formatting the same translated value on every template evaluation.
import { Component, computed, inject, input } from '@angular/core';
import { NgxSignalTranslateService } from 'ngx-signal-translate';
@Component({
selector: 'user-row',
standalone: true,
template: `<span>{{ userLabel() }}</span>`,
})
export class UserRowComponent {
readonly name = input.required<string>();
readonly #translate = inject(NgxSignalTranslateService);
protected readonly userLabel = computed(() =>
this.#translate.translate('HELLO_NAME', { name: this.name() }),
);
}
Service in TypeScript
import { Component, computed, effect, inject } from '@angular/core';
import { NgxSignalTranslateService } from 'ngx-signal-translate';
@Component({
selector: 'demo-logic',
template: '{{ greeting() }}',
})
export class DemoLogicComponent {
readonly #translate = inject(NgxSignalTranslateService);
readonly greeting = computed(() => this.#translate.translate('HELLO'));
constructor() {
this.#translate.setLanguage('en');
effect(() => {
// Runs whenever language resources change
console.log(this.#translate.translate('HELLO_NAME', { name: 'Ada' }));
});
this.#translate.translate$('HELLO').subscribe(console.log);
}
}
Behavior notes
translatereturns the key if the language or key is missing.translate$waits for the language to be selected and loaded before emitting.- Language files load once per language; failed loads resolve to empty resources and also fall back to returning the key.
Breaking changes
21.0.5
- The
signalTranslatepipe has been removed. UseNgxSignalTranslateService.translate()directly in templates instead. Angular's reactive context re-evaluates the expression automatically whenever the language or resources change.
Compatibility
| ngx-signal-translate | Angular |
|---|---|
| - | Newer versions follow Angular versioning. |
| 3.x | >= 20.x.x |
| 2.x | 19.x.x |
| 1.x | 18.x.x |