Releases: ngx-translate/core
v18.0.0
@ngx-translate/core@18.0.0 and @ngx-translate/http-loader@18.0.0 are now stable on npm (latest).
v18 is the major API-cleanup release: standalone providers everywhere, signal-based internals, the default → fallback rename finalized, and the deprecated surface removed. It also resolves three long-standing semantic gotchas and baselines the workspace on Angular 22 / TypeScript 6.0.
Highlights
- Standalone-first setup.
TranslateModuleis gone — useprovideTranslateService()/provideChildTranslateService()(works in standalone and NgModule apps). - New
*translateBlock="let t"structural directive for cleaner template translations. - New
isLoading: Signal<boolean>— true while anyuse()load is in flight; read it for language-switching spinners. - Isolated subtrees are now truly isolated — own events, lookups, and language state.
- Angular 18–22 supported (16 and 17 dropped); built and tested against Angular 18/19/20/21/22.
Breaking changes — required edits
TranslateModule removed. Replace TranslateModule.forRoot({...}) / forChild({...}) with provideTranslateService({...}) / provideChildTranslateService({...}). The pipe, directive, and service are standalone.
Deprecated default* symbols removed — rename:
| Removed | Replacement |
|---|---|
defaultLang |
fallbackLang |
setDefaultLang() |
setFallbackLang() |
getDefaultLang() |
getFallbackLang() |
onDefaultLangChange |
onFallbackLangChange |
DefaultLangChangeEvent |
FallbackLangChangeEvent |
langs |
getLangs() |
setValue() (util) |
insertValue() |
Also removed: useDefaultLang and defaultLanguage config fields (along with TranslateModule).
Deprecated (still works, warns once): using element text content as a key (<span translate>Hello</span>). Use [translate]="'KEY'", the translate pipe, or *translateBlock. It will be removed next major.
Potentially breaking — low impact (behavior changes)
- A failed
use()no longer mutates state. On loader failure,currentLang()/lastUseLanguagestay at the prior value instead of switching to the failed language. UseisLoading()or the returned Observable's error channel to drive switching UI. - Isolated subtrees no longer see ancestor
translationChange$events, nor borrow keys from outer scopes. Isolation now means own events + own lookups + own language state. If you wanted shared translations with subtree-scoped state, useprovideChildTranslateService({ extend: true }). instant()"unloaded language" warning is deduplicated per isolated subtree (was once per service instance).ITranslateServicegainsisLoading: Signal<boolean>. If you mock it viaimplements/extends ITranslateService, addisLoading = signal(false).asReadonly(). See the "Mocking TranslateService" recipe in the README.- Loader errors are now logged instead of silently swallowed.
Migration
Full step-by-step guide: https://ngx-translate.org → Getting Started → Migration Guide.
Angular compatibility: 18, 19, 20, 21, 22 · TypeScript: 6.0 · RxJS: ≥7
v18.0.0-rc.1
💥 npm install fix for the RC pair (reported by @Julien-Marcou)
The http-loader's peer dependency on @ngx-translate/core was ">=18", which npm's semver doesn't match against pre-release versions. Installing both packages at 18.0.0-rc.0 failed with ETARGET. The peer dep is now ">=18.0.0-rc.1", so RC combinations install cleanly — no more overrides workaround needed.
✨ Function-form parameters for translate() (suggested by @Silas770)
TranslateService.translate() and the standalone translate() function now accept arrow functions alongside plain values and Signals. No more separate computed() wrapper for derived inputs:
// Before — needed an extra computed()
model = signal({ currentKey: 'HELLO' });
keyComputed = computed(() => this.model().currentKey);
greeting = translate(this.keyComputed);
// Now — pass the arrow directly
model = signal({ currentKey: 'HELLO' });
greeting = translate(() => this.model().currentKey);Signals still work — Signal<T> is structurally () => T, so existing signal-based call sites compile and run unchanged. The key parameter also now accepts string[] for multi-key lookup, matching get(), instant(), and stream().
Thanks
Thanks to @Julien-Marcou and @Silas770 for the feedback — both reports are addressed in this release.
Keep the feedback coming!
v18.0.0-rc.0
What's new in @ngx-translate/core v18-rc.0
v18 rebuilds ngx-translate on Angular Signals. The library is now fully standalone — TranslateModule is gone — and gains hierarchical service isolation, a block directive for templates, and per-call language selection. Existing template syntax (| translate, [translate]) works as before.
Requires Angular 18 or later. The library uses effect(), takeUntilDestroyed(), and stable signal APIs that are only available from Angular 18+.
Highlights
- Signals everywhere —
currentLang,fallbackLang, internal state management, the pipe, and the directive are all signal-driven. The new standalonetranslate()function returns a reactiveSignal— no subscriptions, no cleanup. *translateBlockdirective — Exposes a typed translation function to a template block. Cleaner than chaining pipes when you need multiple keys in one place.- Hierarchical services —
provideChildTranslateService()creates an isolated child with its own store and loader. Translations resolve child-first, then walk up to the parent.provideTranslateService()creates a fully independent root. - Per-call language override —
translate(),get(),instant(),stream(), andgetParsedResult()accept an optionallangparameter to bypass the current/fallback chain.
BREAKING CHANGES
TranslateModule removed — Impact: High
TranslateModule, TranslateModule.forRoot(), and TranslateModule.forChild() have been removed. Use the standalone provider functions and import the pipe/directive directly:
// v17
@NgModule({
imports: [
TranslateModule.forRoot({
loader: { provide: TranslateLoader, useClass: MyLoader },
compiler: { provide: TranslateCompiler, useClass: MyCompiler },
parser: { provide: TranslateParser, useClass: MyParser },
missingTranslationHandler: { provide: MissingTranslationHandler, useClass: MyHandler },
defaultLanguage: "en",
}),
],
})
// v18 — in bootstrapApplication() or route config
providers: [
provideTranslateService({
loader: provideTranslateLoader(MyLoader),
compiler: provideTranslateCompiler(MyCompiler),
parser: provideTranslateParser(MyParser),
missingTranslationHandler: provideMissingTranslationHandler(MyHandler),
fallbackLang: "en",
}),
]
// Component imports (replace TranslateModule in component imports)
@Component({
imports: [TranslatePipe, TranslateDirective],
})currentLang is now a Signal — Impact: High
TranslateService.currentLang was a plain string getter in v17. In v18 it returns a Signal<Language | null>. Any code that reads it as a string must call the signal:
// v17
if (service.currentLang === "en") { ... }
// v18
if (service.currentLang() === "en") { ... }The upside: currentLang now works directly in computed() and effect(), and Angular's template change detection tracks it automatically — no manual subscriptions needed.
getCurrentLang() can return null — Impact: Medium
The return type changed from Language to Language | null. Before any language is set, it returns null.
Deprecated defaultLang aliases removed — Impact: Medium
defaultLang, setDefaultLang(), getDefaultLang(), and onDefaultLangChange have been removed. These were deprecated v17 aliases for the fallback equivalents:
defaultLang→fallbackLangsignalsetDefaultLang(lang)→setFallbackLang(lang)getDefaultLang()→getFallbackLang()onDefaultLangChange→onFallbackLangChange
Deprecated config options useDefaultLang and defaultLanguage removed — Impact: Medium
These v16-era compatibility options have been removed from RootTranslateServiceConfig. Use fallbackLang instead.
extend config replaced by root/child hierarchy — Impact: Medium
The extend: true config option has been removed. Use provideChildTranslateService() instead — it automatically creates a non-root service. Child services delegate language selection to the root and maintain their own translation loader.
// v17
TranslateModule.forChild({
loader: { provide: TranslateLoader, useClass: FeatureLoader },
extend: true,
})
// v18
provideChildTranslateService({
loader: provideTranslateLoader(FeatureLoader),
})Child services now have their own store — Impact: Medium
provideChildTranslateService() now creates its own TranslateStore instance with a full set of default plugin providers. Child services look up translations in their own store first, then walk up the parent chain — so lazy-loaded modules can still access translations provided by the parent, while local translations take precedence. Child translations never write to the parent store, keeping scopes cleanly separated. To create a fully independent service (no parent fallback), use provideTranslateService() — which creates a root-level service with its own language state and store.
Mixed child content in [translate] elements — Impact: Medium
The directive now sets el.textContent directly for explicit-key bindings, replacing all child content. In v17, individual text nodes were updated, potentially preserving sibling HTML. If you have mixed content inside translated elements, restructure:
<!-- This will lose the <b> in v18 -->
<span [translate]="'GREETING'"><b>Bold</b></span>
<!-- Instead, restructure -->
<span [translate]="'GREETING'"></span>setValue() removed — Impact: Low
The deprecated setValue() utility function has been removed. Use insertValue() instead. Note that insertValue() returns a new object rather than mutating in place:
// v17 (mutation)
setValue(obj, "a.b", 42);
// v18 (immutable — assign the return value)
obj = insertValue(obj, "a.b", 42);TranslateStore rewritten with Angular Signals — Impact: Low
The store's internal state is now held in WritableSignals with public read-only Signal accessors:
translations: Signal<Record<Language, InterpolatableTranslationObject>>languages: Signal<Language[]>lastTranslationChange: Signal<TranslationChangeEvent | null>
The translationChange$ observable is still available for push-based subscribers.
All state updates are now immutable — each setTranslations() or deleteTranslations() call produces a new object reference, enabling proper signal change detection.
Language management moved from store to service — Impact: Low
currentLang, fallbackLang, and their associated getters, setters, and observables (onLangChange, onFallbackLangChange) have been removed from TranslateStore. These responsibilities now live in TranslateService.
getTranslation(key) removed from store — Impact: Low
The convenience method that looked up a key against current + fallback language has been removed because the store no longer tracks language selection. Use TranslateService.instant(key) or store.getTranslationValue(language, key).
getValue() → getTranslationValue() — Impact: Low
The protected getValue(language, key) method is now public and renamed to getTranslationValue(language, key).
onTranslationChange → translationChange$ — Impact: Low
The observable getter onTranslationChange has been replaced by the translationChange$ property. For template-reactive reads, use the lastTranslationChange signal instead.
langs getter removed — Impact: Low
Replace translateService.langs with translateService.getLangs().
currentLoader and compiler are now protected — Impact: Low
These properties are no longer part of the public API. Use the service's public methods instead.
Empty keys no longer throw — Impact: Low
get("") and instant("") now return empty strings instead of throwing an Error. Code that relied on catching those exceptions needs adjustment.
setTranslation() no longer auto-merges with extend — Impact: Low
In v17, setTranslation() would force-merge when the service had extend: true. In v18, merging only happens when shouldMerge is explicitly true.
DefaultLangChangeEvent type removed — Impact: Low
The deprecated type alias has been removed. Use FallbackLangChangeEvent directly.
TranslatePipe rewritten with signals — Impact: Low
The pipe is now powered by TranslateService.translate() signals internally. All manual RxJS subscriptions, ChangeDetectorRef.markForCheck(), and OnDestroy cleanup are gone. Template usage is unchanged — {{ 'KEY' | translate }} works exactly as before. Previously-public internals (lastKey, lastParams, updateValue(), subscription fields) are removed.
TranslateDirective rewritten with signals — Impact: Low
The directive now uses WritableSignals for key/params and an effect() for DOM writes when using explicit key binding ([translate]="'KEY'"). The content-as-key path is delegated to ContentKeyHandler (deprecated). Manual subscriptions replaced by onTranslationRefresh + takeUntilDestroyed. Previously-public methods (checkNodes(), updateValue(), getContent(), setContent()) are removed.
Internal
- Plugin base classes (
TranslateLoader,TranslateCompiler,TranslateParser,MissingTranslationHandler) are unchanged in API and behavior InterpolatableTranslationObjecttype extracted fromtranslate.service.tsintotranslate.service.interface.ts(no consumer impact)
New Features
Hierarchical services with isolation
provideChildTranslateService() creates a child service with its own TranslateStore and loader, scoped to a lazy-loaded module or component subtree. Child services delegate language selection (current/fallback lang) to the root, but l...
v17.0.0
What's Changed
See the migration guide for all changes and how to migrate from v16 -> v17:
https://ngx-translate.org/getting-started/migration-guide/
New Contributors
- @rbalet made their first contribution in #1540
- @Gallimathias made their first contribution in #1530
- @undsoft made their first contribution in #1529
- @gentoo90 made their first contribution in #1515
Full Changelog: v16.0.4...v17.0.0
v16.0.4
What's Changed
- Updated for Angular 19
- Fix: null values are now skipped in translations instead of creating empty objects
- Code improvements, lint warnings
- Chore: Fixed in the README
New Contributors
- @agustiza made their first contribution in #1234
- @Behrouz-B made their first contribution in #1511
Full Changelog: v16.0.3...v16.0.4
v16.0.3
Documentation and Guides
Features
- core: Support for Standalone components in Angular:
TranslatePipe,TranslateDirective, are now stand alone- Introduced
provideTranslateService()to initialise ngx-translate
- core: Parameters and return values now have explicit types instead of
any. Due to TypeScript
limitations,anyis still partially required in recursive type definitions. - core: Introduced
_(id)to tag translations for automated extraction from source code. - core/http-loader: Resolved ESLint warnings, improved overall code quality.
- core/http-loader: Enhanced documentation available at ngx-translate.org.
- core/http-loader: Set MIT License for npm modules.
- core/http-loader: Implemented GitHub Actions for continuous integration.
Fixes
- core: The
use()function now reliably sets the last requested language. - core: Improved the
get(),stream(), getStreamOnTranslationChange methods to recursively process and interpolate results.
Deprecations
- core:
getTranslation()is now deprecated
v15.0.0
15.0.0 (2023-05-09)
Features
- core/http-loader: add support for Angular v16
- core/http-loader: the code for both core & http-loader is now managed with Bit
BREAKING CHANGES
- core/http-loader: ngx-translate is now built for Angular 16, if you use Angular 15 or below please refer to the compatibility table to know which version you can install.
v14.0.0
14.0.0 (2021-11-08)
Features
- core/http-loader: add support for Angular v13 and RxJS 7 (3a4c7ee), closes #1345
- http-loader: the code for http-loader has been moved to this repository
BREAKING CHANGES
- core/http-loader: ngx-translate is now built for Angular 13, if you use Angular 12 or below please refer to the compatibility table to know which version you can install.
The library is now distributed only for ivy as the view engine is no longer supported by Angular.
v13.0.0
13.0.0 (2020-06-26)
Features
BREAKING CHANGES
- core: ngx-translate is now built for Angular 10, if you use Angular 9 or below please refer to the compatibility table to know which version you can install