Internationalization
PrimeCal supports four languages across the full application interface:
| Code | Language |
|---|---|
en | English (default) |
hu | Hungarian |
de | German |
fr | French |
The frontend uses i18next with react-i18next for the React integration and i18next-http-backend for loading translation files at runtime.
Library Stack
| Package | Version | Role |
|---|---|---|
i18next | ^25 | Core i18n engine |
react-i18next | ^16 | React hooks and components |
i18next-http-backend | ^3 | Lazy-loads JSON translation files over HTTP |
i18next-browser-languagedetector | ^8 | Detects user language from browser settings or localStorage |
Translation File Location
Translation files are served from frontend/public/locales/:
frontend/public/locales/
├── en/
│ ├── common.json
│ ├── calendar.json
│ ├── booking.json
│ ├── automation.json
│ └── ...
├── hu/
│ └── (same file names as en/)
├── de/
│ └── ...
└── fr/
└── ...
Files are divided by namespace (one JSON file per feature area per language). The HTTP backend loads them on demand when the namespace is first used.
i18n Initialization
i18next is initialized in frontend/src/i18n/ (exact file may be i18n.ts or config.ts). Key configuration:
i18n
.use(HttpBackend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng: 'en',
supportedLngs: ['en', 'hu', 'de', 'fr'],
defaultNS: 'common',
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json',
},
});
The language detector checks localStorage first (where the user's saved language preference is stored), then browser Accept-Language, then falls back to English.
Using Translations in Components
Use the useTranslation hook from react-i18next:
import { useTranslation } from 'react-i18next';
function CreateEventButton() {
const { t } = useTranslation('calendar');
return <button>{t('actions.createEvent')}</button>;
}
For translations in non-component contexts (utilities, service files), use the useAppTranslation hook from frontend/src/i18n/useAppTranslation.ts, which wraps the standard hook for consistent usage.
Adding a New Translation Key
- Add the key to the English file first:
frontend/public/locales/en/{namespace}.json - Add the same key to
hu,de, andfrwith appropriate translations - Never use placeholder values in non-English locales — write real translations
- Follow existing key group conventions (e.g.
booking.actions.*,automation.triggers.*)
All four locale files must have parity — the same keys must exist in every language. Before merging, run the validation script:
cd backend-nestjs && npm run i18n:validate
This script checks that all keys present in the English baseline exist in every other supported locale.
Backend i18n
The backend uses nestjs-i18n for server-rendered messages (error messages, notification text). Backend translation files live in backend-nestjs/src/i18n/. The backend reads the Accept-Language header or the user's stored language preference to select the correct locale for server messages.
Language Switching
Users set their preferred language during onboarding (CompleteOnboardingDto.language) and can change it in their profile settings. The preference is stored in the database and returned in the user profile response.
On the public booking page (/book/:slug), a standalone LanguageSwitcher component allows unauthenticated visitors to select their language before filling the booking form. The language selection is stored in localStorage and used by the i18next language detector on subsequent visits.
Encoding and BOM
Translation JSON files must be UTF-8 encoded without a BOM. Windows editors may add a BOM to UTF-8 files — this will cause JSON parse failures in the HTTP backend. Verify encoding before committing new locale files.