Internationalization (i18n)¶
Supported Languages¶
MVP (Launch): - 🇷🇺 Russian (Русский) - 🇬🇧 English (English) - 🇨🇿 Czech (Čeština) - 🇵🇱 Polish (Polski) - 🇩🇪 German (Deutsch)
Roadmap: - 🇮🇹 Italian (Italiano) - 🇳🇱 Dutch (Nederlands) - 🇫🇷 French (Français) - 🇪🇸 Spanish (Español)
Language Selection Hierarchy¶
1. User-level (personal preference)
└─ Overrides everything
2. Company-level (default for all users)
└─ Applied on registration
3. Browser-level (detected from Accept-Language header)
└─ Used only for login page before authentication
Implementation (Angular)¶
Setup:
// app.config.ts
import { provideTranslateService, TranslateLoader } from '@ngx-translate/core';
import { HttpClient } from '@angular/common/http';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideTranslateService({
defaultLanguage: 'en',
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
})
]
};
Translation Files:
src/assets/i18n/
├── en.json (English)
├── ru.json (Russian)
├── cs.json (Czech)
├── pl.json (Polish)
└── de.json (German)
Example - en.json:
{
"COMMON": {
"SAVE": "Save",
"CANCEL": "Cancel",
"DELETE": "Delete",
"EDIT": "Edit",
"SEARCH": "Search",
"FILTER": "Filter"
},
"DRIVERS": {
"TITLE": "Drivers",
"ADD_DRIVER": "Add Driver",
"READINESS": {
"READY": "Ready for delivery",
"NOT_READY": "Not ready",
"WARNING": "Warning"
},
"DOCUMENTS": {
"PASSPORT": "Passport",
"DRIVERS_LICENSE": "Driver's License",
"MEDICAL_EXAM": "Medical Examination",
"ADR_CERTIFICATE": "ADR Certificate"
},
"STATUS": {
"ACTIVE": "Active",
"ON_LEAVE": "On Leave",
"INACTIVE": "Inactive",
"TERMINATED": "Terminated"
}
}
}
Example - cs.json:
{
"COMMON": {
"SAVE": "Uložit",
"CANCEL": "Zrušit",
"DELETE": "Smazat",
"EDIT": "Upravit",
"SEARCH": "Hledat",
"FILTER": "Filtr"
},
"DRIVERS": {
"TITLE": "Řidiči",
"ADD_DRIVER": "Přidat řidiče",
"READINESS": {
"READY": "Připraven k přepravě",
"NOT_READY": "Nepřipraven",
"WARNING": "Varování"
},
"DOCUMENTS": {
"PASSPORT": "Pas",
"DRIVERS_LICENSE": "Řidičský průkaz",
"MEDICAL_EXAM": "Lékařská prohlídka",
"ADR_CERTIFICATE": "ADR certifikát"
},
"STATUS": {
"ACTIVE": "Aktivní",
"ON_LEAVE": "Na dovolené",
"INACTIVE": "Neaktivní",
"TERMINATED": "Ukončen"
}
}
}
Usage in Components:
// Component
export class DriversListComponent {
constructor(private translate: TranslateService) {
// Switch language
this.translate.use('cs'); // Czech
}
getReadinessText(driver: Driver): string {
return driver.isReady
? this.translate.instant('DRIVERS.READINESS.READY')
: this.translate.instant('DRIVERS.READINESS.NOT_READY');
}
}
<!-- Template -->
<h1>{{ 'DRIVERS.TITLE' | translate }}</h1>
<button mat-raised-button>
{{ 'DRIVERS.ADD_DRIVER' | translate }}
</button>
<mat-select [(value)]="selectedLanguage" (selectionChange)="switchLanguage($event)">
<mat-option value="en">🇬🇧 English</mat-option>
<mat-option value="ru">🇷🇺 Русский</mat-option>
<mat-option value="cs">🇨🇿 Čeština</mat-option>
<mat-option value="pl">🇵🇱 Polski</mat-option>
<mat-option value="de">🇩🇪 Deutsch</mat-option>
</mat-select>
Date/Time/Number Formatting¶
Angular Pipes with Locales:
// app.config.ts
import { registerLocaleData } from '@angular/common';
import localeCs from '@angular/common/locales/cs';
import localePl from '@angular/common/locales/pl';
import localeDe from '@angular/common/locales/de';
import localeRu from '@angular/common/locales/ru';
registerLocaleData(localeCs);
registerLocaleData(localePl);
registerLocaleData(localeDe);
registerLocaleData(localeRu);
<!-- Template -->
<!-- Date formatting based on locale -->
<p>{{ driver.hire_date | date:'short':'':currentLocale }}</p>
<!-- Czech: 27. 10. 2025 14:30 -->
<!-- English: 10/27/2025, 2:30 PM -->
<!-- German: 27.10.2025, 14:30 -->
<!-- Currency formatting -->
<p>{{ order.total_amount | currency:order.currency:'symbol':'1.2-2':currentLocale }}</p>
<!-- Czech: 1 000,00 Kč -->
<!-- English: €1,000.00 -->
<!-- Polish: 1 000,00 zł -->
Email Templates (Multi-language)¶
Template Structure:
resources/views/emails/
├── drivers/
│ ├── invitation_en.blade.php
│ ├── invitation_cs.blade.php
│ ├── invitation_pl.blade.php
│ ├── invitation_de.blade.php
│ └── invitation_ru.blade.php
└── shared/
└── header.blade.php
Dynamic Template Selection:
// Laravel Mail
Mail::to($driver->email)
->send(new DriverInvitation($driver, $preferredLanguage));
// Mail class
class DriverInvitation extends Mailable
{
public function build()
{
$template = "emails.drivers.invitation_{$this->language}";
return $this->view($template)
->subject($this->getSubject());
}
private function getSubject(): string
{
return match($this->language) {
'cs' => 'Pozvánka do G-Track TMS',
'pl' => 'Zaproszenie do G-Track TMS',
'de' => 'Einladung zu G-Track TMS',
'ru' => 'Приглашение в G-Track TMS',
default => 'Invitation to G-Track TMS',
};
}
}
Last Updated: October 29, 2025 Version: 2.0.1 Source: Master Specification v3.1, Section 13