npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ngx-signal-translate

v22.0.0

Published

Signal-first i18n for Angular: lazy-loaded JSON resources, and a service with sync, signal, and observable APIs.

Readme

NgxSignalTranslate

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), and setLanguage.
  • Placeholder replacement with string | number params.

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

  • translate returns 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 signalTranslate pipe has been removed. Use NgxSignalTranslateService.translate() directly in templates instead. Angular's reactive context re-evaluates the expression automatically whenever the language or resources change.

Compatibility