npm package: @flexzap/providers
Description: All the providers that makes part of the flexzap library
Author: flexzap
Latest version: 1.3.0

# @flexzap/providers

Global application providers and core services for FlexZap applications. Part of the FlexZap Library ecosystem.

## Installation

```bash
npm install @flexzap/providers
```

### Peer Dependencies

This library requires the following peer dependencies:

```bash
npm install @angular/common@^21.1.0 @angular/core@^21.1.0 @ngx-translate/core@^17.0.0 @ngx-translate/http-loader@^17.0.0
```

## Usage

### Localization Provider

To enable localization in your application, use the `provideZapLocalization` function in your application configuration (`app.config.ts`).

```typescript
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';

import { provideZapLocalization, ZapLocalizationConfig } from '@flexzap/providers';

const LOCALIZATION_CONFIG: ZapLocalizationConfig = {
  supportedLangs: ['en', 'fr', 'de', 'nl'],
  defaultLang: 'en',
  assetPath: './assets/i18n/',
  assetSuffix: '-content.json',
  cookieName: 'COOKIE_LOCALIZATION_LANG',
  cookieExpiryDays: 365
};

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(),
    // ...other providers
    provideZapLocalization(LOCALIZATION_CONFIG)
  ]
};
```

#### Accessing Configuration

You can access the configuration object in any component or service using the `ZAP_LOCALIZATION_CONFIG` injection token.

```typescript
import { Component, inject } from '@angular/core';
import { ZAP_LOCALIZATION_CONFIG } from '@flexzap/providers';

@Component({ ... })
export class MyComponent {
  config = inject(ZAP_LOCALIZATION_CONFIG);

  constructor() {
    console.log('Supported languages:', this.config.supportedLangs);
  }
}
```

#### Configuration Options

The `provideZapLocalization` function accepts a configuration object with the following properties:

| Property           | Type       | Default                   | Description                                        |
| ------------------ | ---------- | ------------------------- | -------------------------------------------------- |
| `supportedLangs`   | `string[]` | Required                  | Array of supported language codes (e.g., `['en']`) |
| `defaultLang`      | `string`   | Required                  | The default language code                          |
| `assetPath`        | `string`   | Required                  | Path to the translation assets (e.g., `./assets/`) |
| `assetSuffix`      | `string`   | Required                  | Suffix for translation files (e.g., `.json`)       |
| `cookieName`       | `string`   | `'ZAP_LOCALIZATION_LANG'` | Name of the cookie used to persist selection       |
| `cookieExpiryDays` | `number`   | `365`                     | Number of days until the language cookie expires   |

### Translation Assets

Structure your JSON translation files as follows. You can use simple strings or variable interpolation.

**`assets/i18n/en-content.json`:**

```json
{
  "WELCOME_TITLE": "Welcome to FlexZap",
  "GREETING_MESSAGE": "Hello, {{name}}!"
}
```

### Template Usage

Use the `ZapTranslate` pipe to bind translation keys in your templates. This pipe is a wrapper around `ngx-translate`, so you don't need to import external modules directly.

```typescript
import { ZapTranslatePipe } from '@flexzap/providers';

@Component({
  imports: [ZapTranslatePipe],
  template: `
    <!-- Simple Key -->
    <h1>{{ 'WELCOME_TITLE' | ZapTranslate }}</h1>

    <!-- Key with Variable -->
    <p>{{ 'GREETING_MESSAGE' | ZapTranslate: { name: 'User' } }}</p>
  `
})
export class MyComponent {}
```

### ZapLocalizationService

You can inject `ZapLocalizationService` to manage language switching programmatically.

```typescript
import { Component, inject } from '@angular/core';

import { ZapLocalizationService } from '@flexzap/providers';

@Component({
  selector: 'app-lang-switcher',
  template: `
    <button (click)="switchLang('en')">English</button>
    <button (click)="switchLang('fr')">Français</button>
  `
})
export class LangSwitcherComponent {
  private localizationService = inject(ZapLocalizationService);

  switchLang(lang: string) {
    // Returns an observable that completes when the language is loaded
    this.localizationService.setLanguage(lang);
  }

  getCurrentLang() {
    return this.localizationService.getCurrentLang();
  }
}
```

### Using Translations in Your Components (TypeScript Code)

To do so, you can use the `ZapLocalizationService` to translate them directly.

`ZapLocalizationService` exposes three main methods:

- **`instant(key)`**: Returns the translation instantly. (Synchronous, requires loaded translations).
- **`get(key)`**: Returns an observable that completes. (Waits for loading).
- **`stream(key)`**: Returns an observable that expects new values on language change.

```typescript
import { Component, inject, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { ZapLocalizationService, ZapTranslatePipe } from '@flexzap/providers';

@Component({
  selector: 'app-root',
  imports: [ZapTranslatePipe],
  template: `<h1>{{ 'welcome' | ZapTranslate }}</h1>`
})
export class App implements OnInit, OnDestroy {
  private subscription?: Subscription;
  private translate = inject(ZapLocalizationService);

  ngOnInit(): void {
    // 1. Using get(): Waits for file load, emits once, and completes.
    this.translate.get('demo.greeting', { name: 'John' }).subscribe((text: string) => {
      console.log(`using get(): ${text}`);
    });

    // 2. Using instant(): Synchronous. CAUTION: Returns key if lang not loaded.
    const text2 = this.translate.instant('demo.greeting', { name: 'John' });
    console.log(`using instant(): ${text2}`);

    // 3. Using stream(): Emits on load AND whenever the language changes.
    this.subscription = this.translate.stream('demo.greeting', { name: 'John' }).subscribe((text: string) => {
      console.log(`using stream(): ${text}`);
    });
  }

  ngOnDestroy(): void {
    this.subscription?.unsubscribe();
  }
}
```

## Testing

This library uses Jest for unit testing with zoneless Angular configuration.

### Running Tests

```bash
# From the monorepo root
npm run providers:test            # Run all unit tests with coverage
npm run providers:test:watch      # Run tests in watch mode (no coverage)
```

### Test Configuration

- **Framework**: Jest with jest-preset-angular
- **Environment**: jsdom
- **Configuration**: Zoneless Angular (mandatory)
- **Coverage**: Reports generated at `coverage/flexzap/providers/`

## Development

### Building the Library

```bash
# From the monorepo root
npm run providers:build       # Build directly
ng build @flexzap/providers   # Build using Angular CLI
```

## Publishing

### Build for Publication

```bash
# From the monorepo root
npm run providers:build
```

### Publish to NPM

```bash
cd dist/flexzap/providers
npm publish --access public
```

## Contributing

This library is part of the FlexZap Library monorepo. Please refer to the [main repository](../../../README.md) for contribution guidelines.

### Development Guidelines

- Use standalone components/providers (default behavior)
- Set `changeDetection: ChangeDetectionStrategy.OnPush` where applicable
- Write comprehensive tests with Jest (zoneless configuration)
- Follow semantic versioning for releases

## License

MIT License - see the [LICENSE](../../../LICENSE) file for details.

## Links

- **Homepage**: [https://www.flexzap.dev](https://www.flexzap.dev)
- **Repository**: [https://github.com/vitorazevedo/flexzap-library](https://github.com/vitorazevedo/flexzap-library)
- **Monorepo Documentation**: [Main README](../../../README.md)