Jet provides comprehensive internationalization (i18n) using Transloco, with built-in support for multiple languages, right-to-left (RTL) layouts, and dynamic font loading.
Overview
The i18n system is configured to support English (LTR) and Arabic (RTL) out of the box, with an extensible architecture for adding more languages.
Configuration
Transloco is configured in src/app/app.config.ts:58:
provideTransloco ({
config: {
availableLangs: LANGUAGE_OPTIONS . map (
( languageOption : LanguageOption ) : Language => languageOption . value ,
),
defaultLang: DEFAULT_LANGUAGE_OPTION . value ,
prodMode: ! isDevMode (),
reRenderOnLangChange: true ,
},
loader: TranslocoHttpLoader ,
})
Global Configuration
The transloco.config.ts file defines where translation files are stored:
const config : TranslocoGlobalConfig = {
keysManager: { output: 'public/i18n/' , sort: true , unflat: true },
langs: [ 'ar' , 'en' ],
rootTranslationsPath: 'public/i18n/' ,
};
Translation Loader
Translations are loaded dynamically via HTTP (src/app/transloco-loader.ts:8):
@ Injectable ({ providedIn: 'root' })
export class TranslocoHttpLoader implements TranslocoLoader {
readonly #httpClient = inject ( HttpClient );
readonly #loggerService = inject ( LoggerService );
public getTranslation ( language : Language ) : Observable < Translation > {
return this . #httpClient . get < Translation >( `/i18n/ ${ language } .json` ). pipe (
catchError (( error : Error ) : Observable < Translation > => {
this . #loggerService . logError ( error );
const emptyTranslation : Translation = {};
return of ( emptyTranslation );
}),
);
}
}
Translation files are served from /public/i18n/ as static JSON files, enabling efficient caching and lazy loading.
Language Options
Languages are defined in src/app/constants/language-options.constant.ts:4:
export const LANGUAGE_OPTIONS : LanguageOption [] = [
{
directionality: 'ltr' ,
fontPair: 'ns-bg' ,
fontPairUrl:
'https://fonts.googleapis.com/css2?display=swap&family=Bricolage+Grotesque:opsz,[email protected] ,200..800&family=Noto+Sans:[email protected] ' ,
icon: 'translate' ,
nameKey: marker ( 'constants.english' ),
value: 'en' ,
},
{
directionality: 'rtl' ,
fontPair: 'nsa-nsa' ,
fontPairUrl:
'https://fonts.googleapis.com/css2?display=swap&family=Noto+Sans+Arabic:[email protected] ' ,
icon: 'translate' ,
nameKey: marker ( 'constants.arabic' ),
value: 'ar' ,
},
];
Language Configuration Properties
Text direction for the language
CSS class identifier for the font combination
Google Fonts URL for loading the appropriate fonts
Material icon identifier for the language selector
Translation key for the language name
Language code (e.g., ‘en’, ‘ar’)
Translation Files
Translations are organized in JSON format. Example from public/i18n/en.json:
{
"alerts" : {
"welcome" : "Welcome!" ,
"signed-out-successfully" : "Signed out successfully." ,
"something-went-wrong" : "Something went wrong."
},
"constants" : {
"arabic" : "العربية" ,
"english" : "English" ,
"home" : "Home" ,
"profile" : "Profile" ,
"settings" : "Settings"
},
"jet-sign-in-page" : {
"email" : "Email" ,
"password" : "Password" ,
"sign-in" : "Sign in" ,
"sign-in-to-continue-to-x" : "Sign in to continue to {{ x }}"
}
}
Using Translations
In Templates
Use the transloco directive or pipe:
<!-- Directive -->
< h1 transloco = "jet-home-page.toolbar-title" ></ h1 >
<!-- Pipe -->
< p > {{ 'alerts.welcome' | transloco }} </ p >
<!-- With parameters -->
< p > {{ 'jet-sign-in-page.sign-in-to-continue-to-x' | transloco: { x: 'Jet' } }} </ p >
In Components
Inject TranslocoService:
readonly # translocoService = inject ( TranslocoService );
showWelcomeMessage () {
this . #alertService . showAlert (
this . #translocoService . translate ( 'alerts.welcome' )
);
}
RTL Support
Jet automatically handles RTL layouts when Arabic is selected. The layout direction is applied through CSS custom properties:
.jet-sidenav-container {
& [ dir = ' ltr ' ] {
--jet-animation-multiplier : 1 ;
--jet-safe-area-start : env ( safe-area-inset-left );
--jet-safe-area-end : env ( safe-area-inset-right );
}
& [ dir = ' rtl ' ] {
--jet-animation-multiplier : -1 ;
--jet-safe-area-start : env ( safe-area-inset-right );
--jet-safe-area-end : env ( safe-area-inset-left );
}
}
Dynamic Font Loading
Fonts are loaded dynamically based on the selected language:
English (LTR) : Bricolage Grotesque + Noto Sans
Arabic (RTL) : Noto Sans Arabic
The font switching is handled through CSS classes in src/styles.scss:94:
body {
& .jet-font-pair-nsa-nsa {
@include mat . theme (
(
typography: (
brand - family: $nsa-font-family ,
plain - family: $nsa-font-family ,
bold - weight: 700 ,
medium - weight: 500 ,
regular - weight: 400 ,
),
)
);
}
}
Material Paginator Internationalization
Jet includes a custom paginator intl class (src/app/classes/jet-mat-paginator-intl/jet-mat-paginator-intl.ts) that integrates with Transloco:
providers : [
{ provide: MatPaginatorIntl , useClass: JetMatPaginatorIntl }
]
This ensures Material components display translated text:
{
"paginator" : {
"first-page" : "First page" ,
"items-per-page" : "Items per page:" ,
"last-page" : "Last page" ,
"next-page" : "Next page" ,
"page-x-of-y" : "Page {{ x }} of {{ y }}" ,
"previous-page" : "Previous page"
}
}
Adding New Languages
Create translation file
Add a new JSON file in public/i18n/ (e.g., fr.json)
Update language options
Add the language to LANGUAGE_OPTIONS constant with appropriate font configuration
Update Transloco config
Add the language code to transloco.config.ts: langs : [ 'ar' , 'en' , 'fr' ]
Load appropriate fonts
Specify the Google Fonts URL in the language option configuration
Translation Key Management
Use the marker function for translation keys in constants:
import { marker } from '@jsverse/transloco-keys-manager/marker' ;
export const LANGUAGE_OPTIONS : LanguageOption [] = [
{
nameKey: marker ( 'constants.english' ),
// ...
}
];
The marker function doesn’t translate at runtime but helps the Transloco keys manager extract translation keys from your code.
Best Practices
Organize translations by feature
Group related translations under feature-specific keys like jet-sign-in-page, jet-profile-page, etc.
Keep translation files organized with nested objects for better maintainability: {
"jet-profile-page" : {
"toolbar-title" : "Profile" ,
"save" : "Save"
}
}
Parameterize dynamic values
Use template parameters for dynamic content: 'page-x-of-y' : 'Page {{ x }} of {{ y }}'
Always test your application in RTL mode to ensure proper layout behavior.
PWA Integration
The service worker is configured to prefetch the default language (English):
{
"resources" : {
"files" : [
"/i18n/en.json"
]
}
}
Other language files are loaded on demand when users switch languages.
Next Steps
Theming Learn about dynamic theming with RTL support
PWA Features Explore offline capabilities