The ultimate Angular 18+ Signals-based library for RTL/LTR directionality, Arabic localization, and Google Font orchestration. Zoneless-ready and high-performance.
⭐ Star this on GitHub to support RTL development!
ngx-directo is a high-performance, lightweight Angular library for managing bi-directional (RTL/LTR) layouts, dynamic font orchestration, and localized UI state. Built for the modern web, it is fully zoneless-ready and powered by fine-grained Signals.
- Zoneless Optimized: Zero dependence on NgZone. Perfectly compatible with provideZonelessChangeDetection().
- Reactive Design: Built entirely on Angular Signals for high-performance state updates.
- Smart Detection: MutationObserver-driven script detection for mixed-content isolation.
- Automatic Font Orchestration: Dynamic injection of Google Fonts based on active language state, with optional initial preloading for all configured languages.
- Intelligent Mapping: Built-in support for all major RTL languages (
ar,he,fa,ur, etc.) out of the box. - CSS-Native Animations: Direct injection of --dir-sign and --dir-align variables for zero-JS animations.
npm install ngx-directoInitialize the library in your app.config.ts. Directo is designed to be Zero-Config by default, providing sensible fallbacks for English (LTR) and Arabic (RTL) out of the box.
Directo is designed to be Zero-Config by default, providing sensible fallbacks for English (LTR) and Arabic (RTL) out of the box. For production-grade applications, you can use the built-in DirectoLoader to automate translation loading.
import { ApplicationConfig } from '@angular/core';
import { HttpClient, provideHttpClient } from '@angular/common/http';
import { provideDirecto, DIRECTO_LOADER, DirectoHttpLoader, DirectoFetchLoader } from 'ngx-directo';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideDirecto({
languages: {
ar: {
direction: 'rtl',
fontFamily: 'Cairo, sans-serif',
googleFontName: 'Cairo', // Auto-injected from Google Fonts
localizeDigits: true, // Enables 0-9 to ٠-٩ conversion
},
en: {
direction: 'ltr',
fontFamily: 'Inter, sans-serif',
googleFontName: 'Inter'
}
},
defaultLang: 'en',
preloadAll: true, // Optional: Preloads translations and fonts for all languages on startup (useful for translate pipe with forced languages)
// Option A: Automatic translation loading (using HttpClient)
// Default: ./assets/i18n/{{lang}}.json
loader: {
provide: DIRECTO_LOADER,
useFactory: (http: HttpClient) => new DirectoHttpLoader(http, './assets/i18n/', '.json'),
deps: [HttpClient]
}
// Option B: Native Fetch-based loading (No HttpClient dependency)
// loader: {
// provide: DIRECTO_LOADER,
// useValue: new DirectoFetchLoader('/assets/i18n/{{lang}}.json')
// }
})
]
};If you need complete control over the loading process (e.g., merging multiple JSON files or complex logic), you can still use the APP_INITIALIZER pattern to call setTranslations() manually.
{
provide: APP_INITIALIZER,
useFactory: () => {
const directo = inject(DirectoService);
const http = inject(HttpClient);
return () => firstValueFrom(
http.get(`/assets/i18n/${directo.currentLang()}.json`).pipe(
tap(data => directo.setTranslations(directo.currentLang(), data))
)
);
},
multi: true
}Directo allows you to dynamically update the configuration of a specific language at runtime. This is particularly useful for handling multi-tenant branding overrides, such as changing fonts dynamically.
// Update the font for the 'en' language and automatically inject it
directo.updateLanguageConfig('en', {
googleFontName: 'Roboto',
fontFamily: 'Roboto, sans-serif',
direction: 'ltr'
});Both direction and fontFamily are now fully optional in the language configuration:
- direction: If omitted, Directo dynamically auto-detects the layout direction from the language code (e.g.
'ar'is detected as RTL,'en'as LTR). - fontFamily: If omitted, it defaults to
'inherit'to respect your active stylesheet's typography.
If you just want to use the directives and pipes without advanced font orchestration or translation management, you can skip the configuration entirely or pass an empty object:
providers: [
provideDirecto() // Automatically supports ar, en, he, fa, ur, and more!
]Directo includes an Intelligent Registry. If you call directo.setLanguage('ar'), it automatically knows Arabic is RTL and swaps your entire layout, even if you didn't configure it.
Detects the direction of content (RTL/LTR) automatically using first-strong-character logic.
<p [dirAuto]="dynamicText">{{ dynamicText }}</p>
<p dirAuto>This scans inner text content automatically.</p>Flips icons or elements horizontally only when the app is in RTL mode.
<i dirFlip class="pi pi-chevron-right"></i>Conditionally renders elements based on the active direction.
<div dirOnly="rtl">Only visible in RTL mode</div>Forces inputs to remain LTR. Critical for phone numbers, passwords, and codes.
<input dirInput type="tel" placeholder="+966 5XX">| Pipe | Description | Example |
|---|---|---|
| localize | Multi-strategy localization. Supports direct values, object mapping, or auto-key resolution. | {{ enVal | localize : arVal }} or {{ item | localize : 'name' }} |
| directoTranslate | Resolves static UI strings via dot-notation. Can also force a specific language (optional parameter). | {{ 'KEY' | directoTranslate : 'ar' }} |
| dirMirror | Swaps directional keywords in strings (left <-> right, next <-> prev). | {{ 'chevron-right' | dirMirror }} |
| dirNumber | Transforms Western digits (0-9) to native Arabic-Indic digits (٠-٩). | {{ 2026 | dirNumber }} |
Important
Forced Language Preloading: When using directoTranslate with a forced language code (e.g., {{ 'KEY' | directoTranslate : 'ar' }}), you must configure preloadAll: true in your app.config.ts.
Since forced translations must be resolved synchronously during template rendering, the dictionaries must be loaded upfront.
This is a Senior-level feature: Directo enables "Zero-JS" UI logic by injecting reactive CSS variables into the :root element. This allows you to handle complex directionality in SCSS without a single line of component TypeScript.
--dir-sign:1in LTR,-1in RTL.--dir-align:leftin LTR,rightin RTL.--dir-align-inv: The inverse alignment side.
SCSS Example:
.sidebar {
transition: transform 0.3s ease;
// This automatically slides from the correct side in BOTH RTL and LTR!
transform: translateX(calc(var(--dir-sign) * -100%));
}For projects using the classic @angular/animations DSL, Directo provides a mirroring utility. Note that @angular/animations is an optional peer dependency and is only required if you use this specific helper:
import { mirrorAnimation } from 'ngx-directo';
// Usage in trigger/transition definitionsCopyright (c) 2026 Ahmad Alhafi. All rights reserved. MIT License
