Skip to content
☁️ HitKeep Cloud is coming! Join the Early Access waitlist →

Localizing the UI

The HitKeep dashboard is fully translated into English, German, Spanish, French, and Italian — out of the box, no plugins required. The selected language is stored in the database and follows the user across sessions and devices.

LanguageCodeTranslation file
Englishenfrontend/dashboard/public/i18n/en.json
Germandefrontend/dashboard/public/i18n/de.json
Spanishesfrontend/dashboard/public/i18n/es.json
Frenchfrfrontend/dashboard/public/i18n/fr.json
Italianitfrontend/dashboard/public/i18n/it.json

Users change the interface language in Settings → Preferences. The selected locale is saved to user_preferences.default_locale in the database — it is not a browser-only cookie, so the choice persists when the user logs in from a different device.

Switching language is instant: the dashboard re-renders without a page reload, powered by Transloco.

Numbers and dates automatically reformat to match the locale (e.g. 1.234,56 in German, 1,234.56 in English) via @jsverse/transloco-locale.

Each locale is a single JSON file with nested keys. en.json is the reference — all other files must contain the same key structure with translated values.

{
"nav": {
"dashboard": "Dashboard",
"utm": "UTM",
"utmBuilder": "UTM Builder"
},
"common": {
"actions": {
"save": "Save",
"cancel": "Cancel",
"clearAll": "Clear all"
}
},
"dashboard": {
"title": "Dashboard",
"noData": "No data for this period."
}
}

The top-level namespaces map to feature areas:

NamespaceContents
adminAdmin panel: users, sites, IP exclusions
commonShared buttons, column headers, empty states, filters
dashboardDashboard page and chart labels
funnelsFunnel analytics
goalsGoal tracking
integrationAPI clients and API reference pages
loginLogin and setup screens
navSidebar navigation labels and ARIA strings
preferencesLanguage and theme settings
settingsProfile, security (2FA, passkeys), email reports
sharePublic shared dashboard
sitesSite management
utmUTM analytics page
utmBuilderUTM link builder tool

Some strings contain runtime variables wrapped in {{ }}. Leave the variable names exactly as-is — translate only the surrounding text.

// ✅ Correct
"filters": {
"referrer": "Referred by {{ value }}"
}
// ❌ Wrong — variable name changed
"filters": {
"referrer": "Verwiesen von {{ wert }}"
}

Transloco uses ICU-style plural rules for strings that differ by count. When present, they look like:

"itemCount": "{ count, plural, =0 {No items} =1 {One item} other {# items} }"

Translate the label text inside each plural branch; keep the count, plural, branch keys, and # placeholder unchanged.


1. Fork and clone the repository.

Terminal window
git clone https://github.com/pascalebeier/hitkeep.git
cd hitkeep

2. Copy the English reference file.

Terminal window
cp frontend/dashboard/public/i18n/en.json \
frontend/dashboard/public/i18n/{lang}.json

Replace {lang} with a BCP 47 base tag — e.g. pt for Portuguese, nl for Dutch, ja for Japanese.

3. Translate all values.

Open {lang}.json in your editor and translate every string value. Keep all keys unchanged.

en.json
"save": "Save"
// pt.json
"save": "Salvar"

4. Register the language in app.config.ts.

Add the new code to both availableLangs and langToLocaleMapping:

frontend/dashboard/src/app/app.config.ts
provideTransloco({
config: {
availableLangs: ['en', 'de', 'es', 'fr', 'it', 'pt'], // add 'pt'
defaultLang: 'en',
// ...
},
}),
provideTranslocoLocale({
langToLocaleMapping: {
// existing entries …
pt: 'pt-BR', // or 'pt-PT' — pick the most common regional locale
'pt-BR': 'pt-BR',
}
}),

A locale string maps to a standard IETF locale used by Intl APIs to format numbers and dates correctly.

5. Test locally.

Terminal window
cd frontend/dashboard
npm install
npm start

Open the dashboard, navigate to Settings → Preferences, and switch to your new language. Verify labels, number formats, and date formats all look correct.

6. Submit a pull request.

Include both the new {lang}.json file and the app.config.ts change in your PR. The title should follow Conventional Commits:

feat(i18n): add Portuguese (pt) translation

Found a mistranslation or an untranslated key?

  1. Locate the key in en.json to confirm the English source.
  2. Edit the same key in the target locale file.
  3. Submit a PR with title fix(i18n): correct <lang> translation for <key>.

You do not need to rebuild anything — translation files are loaded at runtime as static JSON.


When a new HitKeep feature ships, new keys are added to en.json first. Existing locale files become incomplete until a contributor translates the additions.

To find keys that are present in English but missing from another locale, run:

Terminal window
node -e "
const en = require('./frontend/dashboard/public/i18n/en.json');
const target = require('./frontend/dashboard/public/i18n/de.json');
function diff(a, b, path = '') {
for (const k of Object.keys(a)) {
const p = path ? path + '.' + k : k;
if (!(k in b)) { console.log('MISSING:', p); }
else if (typeof a[k] === 'object') diff(a[k], b[k], p);
}
}
diff(en, target);
"

Replace de.json with the locale you want to audit.


LayerLibraryRole
Translation stringsTranslocoLoad JSON files, switch language at runtime
Number & date formatting@jsverse/transloco-localeLocalises Intl.NumberFormat / Intl.DateTimeFormat to the active lang
Persistenceuser_preferences.default_locale in DuckDBStores the user’s choice server-side across sessions