Skip to content

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