---
title: "HitKeep Dashboard Localization and Translation Guide | HitKeep"
description: "Learn how HitKeep dashboard localization works, which languages are supported, how Transloco files are structured, and how to contribute translations."
canonical: "https://hitkeep.com/guides/localization/"
---

# HitKeep Dashboard Localization and Translation Guide

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

If you use an AI assistant for dashboard copy work, invoke the canonical contributor skill `hitkeep-i18n` from `.agents/skills` and follow the [local development and contribution guide](https://hitkeep.com/guides/contributing/). It points the assistant at current locale files and patterns while delegating live validation to `hk`. The separate [HitKeep Analytics Agent Skills](https://hitkeep.com/guides/integrations/hitkeep-agent-skills/) are for end-user analytics and production MCP, not repository localization.

Related implementation details live in the main repository under `frontend/dashboard/public/i18n/` and `frontend/dashboard/src/app/core/i18n/`. For product behavior, see [Facts and Limits](https://hitkeep.com/reference/facts-and-limits/) and [Teams and Data Isolation](https://hitkeep.com/guides/admin/teams/).

## Supported Languages

| Language | Code | Translation file |
| --- | --- | --- |
| English | en | frontend/dashboard/public/i18n/en.json |
| German | de | frontend/dashboard/public/i18n/de.json |
| Spanish | es | frontend/dashboard/public/i18n/es.json |
| French | fr | frontend/dashboard/public/i18n/fr.json |
| Italian | it | frontend/dashboard/public/i18n/it.json |
| Dutch | nl | frontend/dashboard/public/i18n/nl.json |
| Portuguese | pt | frontend/dashboard/public/i18n/pt.json |

## How Language Selection Works

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](https://jsverse.github.io/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`.

## Translation File Format

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:

| Namespace | Contents |
| --- | --- |
| admin | Admin panel: users, sites, IP exclusions |
| common | Shared buttons, column headers, empty states, filters |
| dashboard | Dashboard page and chart labels |
| funnels | Funnel analytics |
| goals | Goal tracking |
| integration | API clients and API reference pages |
| login | Login and setup screens |
| nav | Sidebar navigation labels and ARIA strings |
| preferences | Language and theme settings |
| settings | Profile, security (2FA, passkeys), email reports |
| share | Public shared dashboard |
| sites | Site management |
| utm | UTM analytics page |
| utmBuilder | UTM link builder tool |

### Interpolation

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 }}"
}
```

### Pluralisation

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.

---

## Contributing a Translation

### Adding a New Language

**1. Fork and clone the repository.**

```
git clone https://github.com/pascalebeier/hitkeep.git
cd hitkeep
./hk setup
```

**2. Copy the English reference file.**

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

Replace `{lang}` with a [BCP 47](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry) base tag, for example `sv` for Swedish or `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"

// sv.json
"save": "Spara"
```

**4. Register the language in the current runtime configuration.**

Use the existing locale configuration and formatting mappings as the pattern. Register the translation ID and its standard [IETF locale](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry) together so Transloco, OptimusUI, and browser `Intl` formatting agree. The repository can move these definitions over time, so follow the current implementation and `$hitkeep-i18n` instead of copying a file-specific snippet from this guide.

**5. Test locally.**

```
./hk dev
```

Open the dashboard URL returned by `./hk workspace status`, 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 Swedish (sv) translation
```

---

### Fixing an Existing 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>`.

Translation files are loaded at runtime as static JSON, but the change still needs the current change-aware QA profile.

---

### Keeping Translations in Sync

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. Plan and run the current change-aware gates through `hk`:

```
./hk qa plan changed
./hk qa
```

If locale shape drift is suspected, use the synchronization utility identified by the current implementation or `$hitkeep-i18n`, then review every resulting change before keeping it. Do not treat generated translations as reviewed copy.

---

## Tech Stack

| Layer | Library | Role |
| --- | --- | --- |
| Translation strings | Transloco | Load JSON files, switch language at runtime |
| Number & date formatting | @jsverse/transloco-locale | Localises Intl.NumberFormat / Intl.DateTimeFormat to the active lang |
| Persistence | user_preferences.default_locale in DuckDB | Stores the user’s choice server-side across sessions |

[Previous Contributing](https://hitkeep.com/guides/contributing/)[Next Supporting HitKeep](https://hitkeep.com/support/funding/)
