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

translate-angular

v0.1.0

Published

Atomic, modular translation library for Angular standalone applications and components.

Readme

translate-angular

An atomic, modular, and reactive translation library for Angular standalone applications and components.

Features

  • ⚡ Atomic & Modular Scoping: Define micro-dictionaries right next to your components and routes instead of maintaining one massive global JSON file.
  • 🧩 Hierarchical Auto-Merging: Child and component-level translations automatically merge with parent and root scopes up the injector tree without overwriting sibling keys.
  • 💉 Functional Injection (injectTranslate): Easily translate keys programmatically in component TypeScript code with automatic access to locally provided translations.
  • 🌍 Angular Formatting Pipes Integration (idLocale): Dynamically pass active locale codes to Angular's built-in pipes (date, currency, number, percent) so formatted numbers and dates update immediately on language switch.
  • 🌐 Intl-Powered Language Labels: Pass simple language codes (['en', 'da', 'es']) and let the browser's Intl.DisplayNames automatically generate localized labels (e.g. "English", "Dansk", "Español").
  • 🔄 Reactive Forms & RxJS: Built-in userLanguageControl (FormControl<string>), userLanguage getter, setLanguage() helper, and userLanguage$ stream for seamless reactivity.
  • 🛠 Translate Pipe: Simple, performant template interpolation with dynamic variable replacement ({{ varName }}).
  • 📦 Pre-built UI Component: Includes <translate-language-picker-select> for instant drop-in language switching.
  • 🚀 100% Standalone: Pure standalone architecture with zero NgModule boilerplate.

Installation

npm install translate-angular

1. Root Configuration (provideTranslateInitializer)

Configure your application defaults, available languages, and initial translations at bootstrap in app.config.ts.

When fetchTranslations is specified, provideTranslateInitializer automatically wires an APP_INITIALIZER to hold application bootstrap until the translation file has loaded, preventing raw translation keys and layout shifts from flickering on the initial render:

import { ApplicationConfig } from '@angular/core';
import { provideTranslateInitializer } from 'translate-angular';
import { globalTranslations } from './global.translations';

export const appConfig: ApplicationConfig = {
  providers: [
    provideTranslateInitializer({
      defaultLanguage: 'en',
      // Pass simple language codes — labels are automatically generated using browser Intl APIs!
      languages: ['en', 'da', 'de', 'es'],
      // Or provide custom labels where needed:
      // languages: [
      //   { value: 'en', label: 'English' },
      //   { value: 'da', label: 'Dansk' },
      // ],

      // Optional: global base translations
      translations: globalTranslations,

      // Optional: automatically awaited before app renders via APP_INITIALIZER
      fetchTranslations: 'assets/i18n/app.json',
    }),
  ],
};

[!NOTE] provideTranslateRoot is also exported as an alias for backwards compatibility.


---

## 2. Defining Translations (`TranslationMap`)

Translations are defined as key-value objects mapped by language code:

```typescript
// sign-in.translations.ts
import { TranslationMap } from 'translate-angular';

export const signInTranslations: TranslationMap = {
  title: {
    en: 'Welcome back!',
    da: 'Velkommen tilbage!',
  },
  submitButton: {
    en: 'Sign In',
    da: 'Log ind',
  },
  welcomeUser: {
    en: 'Hello, {{ name }}!',
    da: 'Hej, {{ name }}!',
  },
  errorMessage: {
    en: 'Invalid credentials provided.',
    da: 'Ugyldige loginoplysninger.',
  },
};

3. Scoped Component Translation

Attach translations directly to a component using addTranslations(...). You can translate keys both in your HTML template using TranslatePipe and in your TypeScript logic using injectTranslate():

import { Component } from '@angular/core';
import { addTranslations, injectTranslate, TranslatePipe } from 'translate-angular';
import { signInTranslations } from './sign-in.translations';

@Component({
  selector: 'app-sign-in',
  imports: [TranslatePipe],
  providers: [addTranslations(signInTranslations)],
  template: `
    <h2>{{ 'title' | translate }}</h2>

    <!-- Interpolation with dynamic variables: {{ name }} -->
    <p>{{ 'welcomeUser' | translate: { name: userName } }}</p>

    <button (click)="onSubmit()">{{ 'submitButton' | translate }}</button>
  `,
})
export class SignInComponent {
  // injectTranslate() automatically captures the component's injector & provided translations!
  private translate = injectTranslate();
  userName = 'Thomas';

  onSubmit() {
    // In TypeScript code — no need to re-pass signInTranslations:
    const error = this.translate('errorMessage');
    const greeting = this.translate('welcomeUser', { name: this.userName });

    console.log(greeting, error);
  }
}

[!TIP] Hierarchical Merging: Translations provided at the component level do not overwrite global or parent translations. They are merged into the scope tree, allowing local overrides and additions.


4. Synchronizing Angular Formatting Pipes (idLocale Pipe)

Angular provides powerful built-in formatting pipes such as DatePipe, CurrencyPipe, DecimalPipe, and PercentPipe. All of them accept a locale?: string parameter, but Angular does not natively re-evaluate them when the user changes language at runtime.

The idLocale pipe solves this problem. It listens to the active language in TranslateService and dynamically converts language codes into standard BCP 47 locale identifiers (e.g. 'da' -> 'da-DK', 'en' -> 'en-US').

By piping a dummy value through ('' | idLocale) into the locale parameter of Angular's pipes, your formatted dates, numbers, and currencies update automatically whenever the user switches language!

Template Examples:

import { Component } from '@angular/core';
import { CurrencyPipe, DatePipe, DecimalPipe, PercentPipe } from '@angular/common';
import { IdLocalePipe } from 'translate-angular';

@Component({
  selector: 'app-checkout-summary',
  imports: [DatePipe, CurrencyPipe, DecimalPipe, PercentPipe, IdLocalePipe],
  template: `
    <!-- DatePipe: formatted according to the active language -->
    <p>Order Date: {{ orderDate | date: 'fullDate' : '' : ('' | idLocale) }}</p>

    <!-- CurrencyPipe: dynamic currency formatting and symbols -->
    <p>Total: {{ totalAmount | currency: 'EUR' : 'symbol' : '1.2-2' : ('' | idLocale) }}</p>

    <!-- DecimalPipe: comma/dot separators automatically adapt -->
    <p>Weight: {{ weightKg | number: '1.2-2' : ('' | idLocale) }} kg</p>

    <!-- PercentPipe: percentage formatting according to active locale -->
    <p>Discount: {{ discountRate | percent: '1.1-2' : ('' | idLocale) }}</p>
  `,
})
export class CheckoutSummaryComponent {
  orderDate = new Date();
  totalAmount = 1499.5;
  weightKg = 1250.75;
  discountRate = 0.15;
}

How idLocale Works:

  1. When the active language is 'da', ('' | idLocale) emits 'da-DK'.
  2. When the active language switches to 'en', ('' | idLocale) emits 'en-US'.
  3. Because IdLocalePipe is an impure pipe listening to userLanguage$, it automatically marks the view for check whenever the language changes, re-rendering Angular's formatting pipes instantly.

5. Reactive Language Control (TranslateService)

TranslateService provides full programmatic and reactive control over application languages:

import { Component, inject } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { TranslateService } from 'translate-angular';

@Component({
  selector: 'app-custom-language-switcher',
  imports: [ReactiveFormsModule],
  template: `
    <!-- Direct two-way binding using the built-in FormControl -->
    <select [formControl]="translateService.userLanguageControl">
      @for (option of translateService.options; track option.value) {
        <option [value]="option.value">
          {{ option.label }}
        </option>
      }
    </select>

    <p>Current language: {{ translateService.userLanguage }}</p>
  `,
})
export class CustomLanguageSwitcherComponent {
  protected readonly translateService = inject(TranslateService);

  setDanish() {
    // Switch language programmatically with setLanguage()
    this.translateService.setLanguage('da');
    // Equivalent to: this.translateService.userLanguageControl.setValue('da');
  }

  checkCurrentLanguage() {
    // Synchronously read active language code
    console.log('Active language:', this.translateService.userLanguage);
  }

  observeLanguage() {
    // React to language changes via RxJS Observable
    this.translateService.userLanguage$.subscribe((lang) => {
      console.log('Language changed to:', lang);
    });
  }
}

Key Service Members:

  • userLanguage: Synchronous getter returning the active language code (string), e.g. 'en'.
  • setLanguage(lang: string): Helper method to change the active language programmatically.
  • userLanguageControl: Non-nullable FormControl<string> initialized with defaultLanguage.
  • userLanguage$: Replayed Observable<string> emitting the current language and all subsequent changes.
  • languageOptions$: Replayed Observable<LanguageOption[]> emitting the resolved language choices for dropdowns.
  • languageOptions: Synchronous getter returning the current array of LanguageOption[].
  • options: Synchronous getter for readonly LanguageOption[].
  • setOptions(options: LanguageOption[]): Dynamically updates the available language options.
  • translate(key, translation, vars?, language?): Synchronous translation method.
  • translate$(key, injector?, vars?, language?): Observable translation lookup supporting reactive subscriptions.

6. Pre-built Drop-in Component (LanguagePickerSelect)

If you want a ready-made language dropdown out of the box, import LanguagePickerSelect:

import { Component } from '@angular/core';
import { LanguagePickerSelect } from 'translate-angular';

@Component({
  selector: 'app-header',
  imports: [LanguagePickerSelect],
  template: `
    <header>
      <h1>My App</h1>
      <translate-language-picker-select />
    </header>
  `,
})
export class HeaderComponent {}

(Note: <atomic-language-picker-select /> is also supported as an alias).


7. Loading External / Remote Translations (fetchTranslations)

To load remote translation JSON files dynamically, use fetchTranslations(url).

Automatic Promise Caching

All fetched translations are automatically cached by URL (accepting string, URL, or standard Request objects). In-flight promises and completed responses are shared across components, routes, and subscriptions. If the user navigates away and returns to a lazy route, the library reuses the cached translations instantly with zero duplicate network requests:

import { Component } from '@angular/core';
import { fetchTranslations, TranslatePipe } from 'translate-angular';

@Component({
  selector: 'app-lazy-feature',
  imports: [TranslatePipe],
  providers: [
    // Automatically cached by URL — route re-visits will not re-fetch from network
    fetchTranslations('https://api.example.com/translations/feature.json'),
  ],
  template: ` <p>{{ 'featureTitle' | translate }}</p> `,
})
export class LazyFeatureComponent {}

API Summary

| Export | Type | Description | | ------------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------- | | provideTranslateInitializer(config?) | Function | Configures root settings and initializes translations via APP_INITIALIZER before bootstrap. | | provideTranslateRoot(config?) | Function | Alias for provideTranslateInitializer. | | addTranslations(map) | Function | Scoped provider that merges micro-dictionaries into the current injection tree. | | fetchTranslations(url) | Function | Scoped provider that fetches translations from a URL with automatic in-memory Promise caching. | | injectTranslate(injector?) | Function | Functional injection helper returning a translate function bound to the component's injector. | | TranslatePipe (translate) | Pipe | Translates keys in templates with variable substitution ({{ varName }}). | | IdLocalePipe (idLocale) | Pipe | Emits active BCP 47 locale string to synchronize Angular pipes (date, currency, number). | | TranslateService | Service | Provides userLanguage, setLanguage(), userLanguageControl, languageOptions$, translate(), etc. | | LanguagePickerSelect | Component | Pre-styled language dropdown selector (<translate-language-picker-select>). | | TranslationMap | Interface | Type definition for translation dictionary structures. | | TranslateConfig | Interface | Configuration options passed to provideTranslateInitializer. | | LanguageOption | Interface | Represents an option in the language dropdown ({ value, label }). |


License

MIT